**Show HN:** *Luma 依存型クロマ圧縮アルゴリズム(画像圧縮)*

2026/02/04 20:13

**Show HN:** *Luma 依存型クロマ圧縮アルゴリズム(画像圧縮)*

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

本稿では、ブロックごとに単純な線形モデルを用いて輝度からCrおよびCbを予測する軽量クロマチャネル圧縮器を提示しています。
各小さなブロック(16×16、8×8、4×4、または2×2)に対して、最小二乗法で2つの係数が計算され、(C_1=a,Y_{\min}+b) と (C_2=a,Y_{\max}+b) の値だけを 8 ビット数として保存します。
クロマは次式で再構築されます
[ C(Y)=\frac{(Y-Y_{\min})(C_2-C_1)}{(Y_{\max}-Y_{\min})}+C_1, ]
したがって各クロマチャネルはブロックあたりわずか 16 ビット(合計 32 ビット)で済みます。最小のブロックではさらにビットを節約するために 6 ビット値が使用されます。分割ビットはブロックが細分化されているかどうかを示し、線形デブロッキングが追加コーディングコストなしでエッジ誤差を平滑化します。
実験により、アーティファクトレベルの増加(3.1 %、1.3 %、0.8 %)に対して平均クロマ bpp が 0.5、0.2、および 0.13 であることが示されました。将来の作業には、エントロピー符号化(gzip/lz4)、(C_1,C_2) のデルタ/DPCM エンコーディング、代替のロスレスコード、誤差閾値に基づく適応デブロッキングが含まれます。
現在の C++ 実装(GitHub 上の “yuvlab”)は実験的であり、ビデオパイプラインや組み込みシステムに有益な高速かつ低オーバーヘッドのクロマ圧縮器を提供しますが、まだ本番環境向けには準備されていません。

本文

タイトル
0.5 bpp以下でクロマデータを圧縮する簡単な手法


はじめに

この記事では、画像のクロマ(色差)データを平均 0.5 ビット/ピクセル (bpp) 未満に圧縮しつつ、目立つアーティファクトが生じない方法について説明します。


クロマとは何か?

画像・映像圧縮でよく使われる手法のひとつは、RGB から YCrCb(または YUV)へ変換してから圧縮することです。
色を赤・緑・青チャンネルではなく、次のように表現します。

  • Y – 明度(ルミナンス)
  • Cr – 色差‑赤
  • Cb – 色差‑青

主な利点は、明度チャネルが視覚情報の大部分を担うため、色差チャネルを低解像度で表現しても人間の目にほとんど気づかないという点です。この考え方は 1930 年代から 1960 年代のカラー TV でも採用されていました。

注記:本記事では、クロマを圧縮・復元する際に明度チャネル(Y)が利用できると仮定します。明度情報自体は DCT のような周波数変換で別途圧縮されるケースが多いですが、その詳細は省略します。


重要な観察点:クロマ ≈ 明度

カラー画像のクロマチャネルを眺めてみると、クロマチャネルは明度チャネルに非常に似ています。
物体やエッジが同じ場所に現れ、クロマチャネルの微細パターンも明度チャネルに存在します。
言い換えれば、何らかの賢い変換関数を使えば、明度チャネルからクロマチャネルを導出できるはずです。


明度からクロマを近似する

画像全体に対して単一の正確なマッピングを見つけるのは難しいですが、問題を 16 × 16 ピクセル程度の小さなブロックに分割すれば扱いやすくなります。

クロマ値が明度値にどのように依存するかを線形近似します:

[ C(Y)=a,Y+b ]

:
1 つの 16 × 16 ブロック(256 個のサンプル)で最小二乗法で直線をフィットすると、(a=0.6504,;b=124.8751) が得られます。

図 2:ある 16 × 16 ブロックに対する Cr と Y の関係の近似。

(a) と (b) がわかれば、線形近似を効率的に符号化する方法として次の 2 つの値を用います:

[ C_1 = a,Y_{\min}+b,\qquad C_2 = a,Y_{\max}+b ]

ここで (Y_{\min}) と (Y_{\max}) はブロック内の最小・最大明度です。
これら 2 点は ((Y_{\min},C_1)) と ((Y_{\max},C_2)) を結ぶ直線を記述します。

上記例:
(Y_{\min}=47,; Y_{\max}=80,; C_1=155.4,; C_2=176.9)。

復元は次の式で行います:

[ C(Y)=\frac{(Y-Y_{\min})(C_2-C_1)}{Y_{\max}-Y_{\min}}+C_1 ]

注記:(Y_{\min}) と (Y_{\max}) は復号時に明度チャネルから計算できるため、符号化データには保存する必要がありません。

(C_1) と (C_2) をそれぞれ 8 ビットで表現すれば、ブロックあたり 16 ビット(Cr 用)と 16 ビット(Cb 用)が必要です。
つまり両チャネル合わせて 32 ビット(4 バイト) がブロック単位の符号化データとなります。


可変ブロックサイズ

線形近似はある条件下でうまく機能しますが、ブロックごとに精度が異なります。
最適圧縮を実現するには大きいブロックを使いたい一方、クロマが線形関数でうまく表せない箇所では小さいブロックが必要です。

手法

  • 近似誤差が設定した品質閾値を超えたら、大きなブロックを 4 等分します。
  • 必要に応じて再帰的に分割を繰り返します。

図 3:1 つの大きいブロックを 7 個の小さいブロックへ分割する例。

ブロックごとに追加で 1 ビットだけを保存すれば十分です:

0 = ブロックを分割しない
1 = 4 等分してサブブロック化

典型的なブロックサイズは以下の通りです。

  • 16 × 16
  • 8 × 8
  • 4 × 4
  • 2 × 2

最小ブロックサイズでは「分割」ビットを保存する必要がありません。
また、最小ブロックでは圧縮率が低いため、クロマ値の表現に 6 ビット(8 ビットではなく)を使用します。
小さなブロックは高周波領域でのみ必要となり、精度よりも速度が重視されます。

図 4:色付き画像全体に対する可変ブロックサイズ – エッジ近くでは小さいブロックが頻出します。

明確なクロマディテールがある領域でも、大きいブロックは luma‑to‑chroma マッピングのおかげでうまく機能します(以下の「クロマのみ」画像参照)。

図 5:画像中で可変ブロックサイズがどのように使用されているかを詳細に示す図。


ブロックアーティファクトへの対処

線形近似の副作用として、特に誤差許容度が大きい(攻撃的圧縮)場合にはブロックが目立つことがあります。
勾配や鋭いエッジは「ブロッキー」に見える可能性があります。

解決策
各ブロックの境界周辺で誤差を推定し、隣接ブロックから線形補間した誤差値を差し引きます。
1 次元例で説明すると:

図 7:線形補間によるエッジ誤差の推定と補正。

2 次元では X と Y の両方向に線形補間を行い、ピクセルが左/右エッジに近ければ X 補間、上/下エッジに近ければ Y 補間を重視します。

結果
ブロック境界の可視性は低減されますが、色がぼやけ(カラーリーク)ることがあります。
一般的には、鋭いエッジよりもぼやけたクロマの方が目立たないため、トレードオフとして受け入れられるケースが多いです。

図 8:大きなブロックをスムージングした結果、ブロッキーさが減少。

この手法は圧縮データストリームに追加情報を必要としません。
エッジ誤差を推測するためアルゴリズムが若干のアーティファクトを生むことがありますが、小さいブロックや高解像度画像では、拡大してもほぼ目立ちません。


実験結果

圧縮レベルクロマ bpp観察
元データ16 bpp(未圧縮)
0.5 bpp (3.1 % of original)0.5通常は視覚的アーティファクトがほぼ見られない(火炎を近くで観察)
0.2 bpp (1.3 % of original)0.2一部色がやや洗われる(バイク、木など)
0.13 bpp (0.8 % of original)0.13最大圧縮。明らかなアーティファクト。色がぼやけて洗われる

サムネイルをクリックするとフルサイズ画像を閲覧できます。

データソース

  • Kodak Lossless True Color Image Suite – kodim05, kodim23
  • Fire breathing 2 – Luc Viatour (Wikimedia Commons)
  • Frühling blühender Kirschenbaum – Wikimedia Commons

実装コードは GitHub の yuvlab リポジトリに公開しています。


今後の改善点

エンコーディング

  • gzip, lz4 などのエントロピー符号化でパック済みクロマデータをさらに 30–50 % 圧縮。
  • 隣接ブロック間の類似性を利用した差分予測。
  • 非線形クロマ値をエンコード:例えば ((C_1+C_2)/2) と ((C_2-C_1)/2) を別々に符号化し、後者を「デルタ」として扱う。
  • Huffman, deflate など他の無損圧縮アルゴリズムも検討。

デブロッキング

現在のデブロッキングは隣接ブロック全ての差分を誤差と仮定するため、鋭いクロマ変化近辺でスムージングアーティファクトが生じる可能性があります。

改善案:

  • 近似誤差が低いブロックではデブロッキングをオフにし、その情報を 1 ビットで保存(追加ビット)。
  • エンコーダの誤差閾値を画像全体の定数として送信し、そこからデブロッキング量を調整。

ソフトウェア

インタラクティブな Web ツールや、クリーンな API とサンプルツールを備えたライブラリを提供すれば、アルゴリズムの普及が促進されます。


免責事項

本記事で説明するアルゴリズムは、実験と試行錯誤(AI の支援なし)により独自に開発されたものです。
色空間変換・線形回帰・適応分割・補間など既知の手法を組み合わせているため、新規性があるかどうかは不明です。


同じ日のほかのニュース

一覧に戻る →

2026/02/08 6:45

小型 C コンパイラ

## Japanese Translation: Tiny C Compiler(TCC)は、非常に小さな(約100 KBのx86実行ファイル)Cコンパイラであり、1回のステップでコンパイル・アセンブル・リンクを行い、バイトコード層なしでネイティブx86マシンコードを生成します。2.4 GHz Pentium IV上では、Links BrowserテストをGCC(20.0 秒)より約10倍速く実行できます(2.27 秒)。これは別のコンパイルステージが不要であるためです。 TCCはISO C99を完全にサポートし、自身をコンパイルでき、任意のC動的ライブラリを直接リンクすることも可能です。完全なプリプロセッサ、GNUスタイルのアセンブラー構文、オプションのメモリと境界チェック機能、さらにはシェバンベースの「Cスクリプト」まで含まれ、コマンドラインから実行できます。libtccライブラリにより、他のプログラムがTCCをランタイムコード生成のバックエンドとして使用できるようになります。 性能テストはPentium IV上で行われました。新しい測定値(参照1–4)では、モダンハードウェアでも速度向上が継続しています。ドキュメント、メールリストサポート、およびSavannah/GitHubリポジトリは最新情報を提供します。 TCCはGNU Lesser General Public License(LGPL)の下で配布されており、商用利用も許可されています。

2026/02/08 8:23

**良質なコードの静かな終焉**

## Japanese Translation: 著者は中学時代から「Good Code™」―読みやすく、保守しやすく、特定の目的を持って存在するコード――を書き続けることに情熱を注いできました。機能提供に重点を置くソフトウェアエンジニアとして、彼は今日の高速開発環境で良いコードがますます希少になっていると感じています。 同僚の経験はこの状況をよく示しています。外部Linuxカーネル統合システムをCからRustへ書き換えた後、最初のバージョンは機能していたものの読みづらく保守が困難でした。原始的なCロジックを学習した上で再度書き直すと、コードはクリーンになり、自明であり、元のCよりも優れていると言えるようになりました。この経験が著者に品質コードへの熱意を再燃させました。 現在、彼はほとんどの場合初期バージョンを書かず、代わりに「Good Code™」ではなく許容できるものを生成するコーディングエージェントに頼っています。このようなツールへの継続的な依存が個々の行レベルでの品質への注意を薄め、業界実務におけるGood Codeの静かな消滅を招くと彼は恐れています。コード品質が低下すると保守コストや技術的負債が増大し、開発者の生産性、製品の信頼性、そして最終的には企業から提供されるソフトウェアへのユーザーの信頼まで損なわれます。

2026/02/08 2:39

**セクターC:512バイトで実装されたCコンパイラ**

## Japanese Translation: SectorCは、x86‑16アセンブリで完全に書かれたCコンパイラで、単一の512バイトのブートセクタに収まります。Ultra‑compactなトークン化スキーム「Barely C」を使用しており、各スペース区切り語を「メガトークン」とみなし、`atoi()`で識別子をハッシュし64Kテーブルに格納します。変数はこのハッシュを通じてセグメント0x3000に保存されます。最初のBarely C実装は468バイトで、シンボルテーブルなしの再帰下降パーサーでした。バイトスレッド化されたForth風の変種も試みられましたが、サイズをさらに削減することはできませんでした。 最終的なコンパイラはわずか **303 バイト** です。サイズは、フォールスルーロジック、テイルコール、コールフュージョン、`lodsw/stosw`の広範な使用、およびすべてのジャンプオフセットを1バイト内に収めるなどの手法で削減されました。残り約200バイトでBarely Cは完全なCサポートへと拡張されました:ネストされたif/whileブロック、包括的な演算子集合(+, −, *, &, |, ^, <<, >>, ==, !=, <, >, <=, >=)、ハッシュテーブルを介した関数定義と再帰、インライン`asm`ステートメント、および単一行(`//`)と複数行(`/* */`)コメントの両方が実装されました。 コンパイラのランタイムは `rt/` ディレクトリ内の2つのCファイルに分かれています:ライブラリルーチン(多くの場合インラインasmを含む)を持つ `lib.c` とエントリポイントとして機能する `_start.c` です。これらはプログラムソースと結合してからコンパイルされます。記事には、全ブートセクタのBase64文字列、VGAモード0x13hで動くサイン波を描画するデモ、および追加例(`hello.c` はビデオメモリ0xB8000に書き込み、`twinkle.c` はPCスピーカーで「Twinkle Twinkle Little Star」を再生)が含まれています。この作業は、512バイトという一見不可能な目標—完全機能のCコンパイラを実現すること—が、創造的なトークン化、ハッシュ化、および積極的なコードサイズ最適化によって達成できることを示しています。