gazou-compressor.jp

AVIFの適応的クロマサブサンプリング:4:2:0/4:2:2/4:4:4自動選択でテキスト滲みと容量を両立

AVIFで UI/テキストを含む複合画像を 一律4:2:0 にすると文字滲みや色縁が発生します。Adaptive Chroma は 領域ごとに最小限だけ4:4:4を適用 し容量を押さえる戦略です。

TL;DR
  • 勾配+彩度変化で 4:4:4 必要領域を抽出
  • 中間は 4:2:2、残り 4:2:0
  • PSNR/SSIM/bytes をCI比較し回帰検知

1. なぜ領域別か

全フレーム/全領域4:4:4は容量コストが高く Adaptive Q と併用時にレイテンシを増加させます。領域限定で知覚差損が集中する テキスト/細線/肌色境界 を守ります。

2. 領域検出

// 1. エッジ/彩度勾配検出 (pseudo)
for (const block of blocks){
  const g = sobel(block.luma); // 輝度勾配
  const sc = saturationGradient(block.rgb);
  block.edgeScore = 0.6*g + 0.4*sc;
}
// 2. 閾値判定 -> ターゲットサンプリングレベル
const EDGE_T = 0.42;
for (const block of blocks){
  if (block.edgeScore > EDGE_T) block.target = '444';
  else if (block.edgeScore > EDGE_T*0.6) block.target = '422';
  else block.target = '420';
}

3. ブロックマップ平滑化

// 3. 小領域マージ (8x8未満と孤立)
mergeSmallComponents(blocks, { minArea:4 });
smoothIsolated(blocks);

孤立ノイズは4:4:4メリットが乏しいのでマージ。塗り潰し (flood fill) 後に面積閾値で再評価します。

4. エンコード分割

// 4. サブサンプリングごとにタイル分割 AVIFエンコード
const byMode = groupBy(blocks, b=>b.target);
for (const mode of ['444','422','420']) {
  const subset = byMode[mode];
  if (!subset?.length) continue;
  encodeAvif(subset, { chroma: mode });
}

タイル単位の再構築が困難な実装では 4:4:4レイヤを別エンコードしアルファ合成 という近似も選択肢です。

5. モデル設計

初期段階は 単純加重スコア で十分です。精度拡張時のみ軽量 GBDT / tiny CNN を検討。推論コスト (<0.8ms/MPix) を守ることが最優先。

// 領域特徴量抽出 (拡張例)
for (const block of blocks){
  block.features = {
    edge: sobel(block.luma).mean(),
    satGrad: saturationGradient(block.rgb),
    contrast: localContrast(block.luma),
    entropy: shannon(block.luma)
  };
}
// シンプル線形閾値を学習 (擬似)
function classify(f){
  const s = 0.9*f.edge + 0.7*f.satGrad + 0.4*f.contrast + 0.2*f.entropy;
  if (s > 1.15) return '444';
  if (s > 0.75) return '422';
  return '420';
}

6. 評価/指標

テキスト/細線マスク (GT) と推定 4:4:4 領域の F1 が 0.9 付近なら多くのUIで視覚破綻は抑制可能。帯域削減率 (full444比) との二軸を可視化し妥協点を選びます。

# 評価ベンチ (macro F1 / 帯域)
python eval.py --pred adaptive.map --gt text_mask.png --metrics f1,precision,recall
node scripts/size-compare.js adaptive.out 444.out

7. 運用/監視

分布変化 (例: 444割合が月次 +8pp) は検出ルール改悪 or 新UI型登場を示唆。メトリクスを時系列で保持し 割合ドリフト をアラート化。

# 運用メトリクス (Prometheus text)
adaptive_chroma_blocks_total{mode="444"} 1820
adaptive_chroma_blocks_total{mode="422"} 640
adaptive_chroma_blocks_total{mode="420"} 4100

8. 失敗パターン

# 失敗パターン再昇格ワークフロー
node scripts/chroma-analyze-drift.js --since 30d --edge-miss-th 0.04

9. CI検証

# CI: 代表画像でクロマ自動 vs フル4:4:4 を比較
node scripts/chroma-adaptive.js --image ui.png --out adaptive.json
node scripts/encode-avif.js --image ui.png --chroma 444 --out full444.json
node scripts/metrics-compare.js adaptive.json full444.json \
  --psnr-threshold -0.15 --ssim-threshold -0.002

差分が閾値超過した領域のみ4:4:4へ再昇格する 適応しきい値再学習 を週次で行うと安定します。

10. FAQ

11. まとめ

Adaptive Chroma により “必要な所だけ4:4:4” を実現し、従来4:4:4固定より容量を 8〜18% 削減しながら文字滲みを解消できます。

gazou-compressor.jp 編集部

画像圧縮・変換・背景除去などの実践テクニックと、Webで“速く・軽く・崩さない”ためのノウハウを発信しています。

関連記事

トピック/更新日の近いコンテンツ