5.19. 階調補正

階調補正は、撮影した画像の中で明るさとカラーがどのように分布しているかを変更します。フレームが暗すぎる、明るすぎる、平坦すぎる、あるいは誤ったカラーに偏っている場合に、アプリケーションが適用する修正です。

これらの補正は2つの系統に分かれます。明るさを再分布する明るさとコントラストの調整と、各ピクセルが何色として読み取られるかを変更するカラーの調整です。どちらもセンサーの ISP に対応する処理があり、ISPは取り込み時に各フレームを補正します。ここで紹介するメソッドは、すでに撮影された Image に対して後から適用するもので、ISPが行った補正よりもさらに多くの補正がフレームに必要なケースに対応します。

5.19.1. ヒストグラム平坦化

最も単純なコントラストストレッチ操作が ヒストグラム平坦化 です。その考え方は、出力のヒストグラムができるだけ平坦になるようにピクセル値を再マッピングし、すべての値がほぼ均等な頻度で現れるようにすることです。視覚的な効果としては、低コントラストの画像(ヒストグラムが狭い帯域に集中しているもの)が、ピクセルが 0 -- 255 の全範囲をカバーする高コントラストの画像になります。

histeq() が平坦化を実行します:

img.histeq()

その仕組みは直接的です。元画像のヒストグラムの累積分布関数(CDF)が計算され、各入力ピクセル値はCDF上の位置にマッピングされ、出力範囲にスケーリングされます。ピクセルがすでに均等に分布していた箇所では、マッピングは恒等変換に近くなります。ピクセルが1つの明るさに積み重なっていた箇所では、その明るさをより広い出力値の範囲に引き伸ばすことでピクセルを分散させます。

低コントラストのシーンでは結果は劇的です。薄暗い室内写真とhisteq適用後の同じ写真との違いは、しばしば「判読不能」と「完全に読み取れる」との違いになります。トレードオフは、この操作がセンサーノイズを含む すべて を増幅することです。回復すべき本物の低コントラストのディテールがあるシーンではhisteqが正解です。clean で適正露出のシーンで単にそれが不要な場合、histeqは目に見えるノイズをもたらします。

5.19.2. CLAHE: 適応的平坦化

ヒストグラム平坦化はグローバルです。画像全体から計算された1つのCDFを用い、それをどこでも一様に適用します。これは明るさの範囲がほぼ均一な画像では機能しますが、局所的に暗い領域と明るい領域があるシーンでは失敗します。CDFはピクセル数の多い側に引っ張られ、反対側は過補正されてしまうのです。

適応的な変種が Contrast Limited Adaptive Histogram Equalisation(コントラスト制限付き適応的ヒストグラム平坦化)で、一般にCLAHEと呼ばれます。CLAHEは1つの グローバル なCDFの代わりに、画像の小さなタイルごとに別々のCDFを計算し、各タイルを自身のCDFに対して平坦化し、タイルの境界を互いにブレンドします。その結果、明るさの調整が 局所的 に行われます。影になった隅は、明るい隅に誤った方向へ引っ張られることなく、自身の平坦化を受けるのです。

adaptive=True フラグは histeq() をCLAHEモードに切り替えます:

img.histeq(adaptive=True, clip_limit=10)

clip_limit パラメータは、その名前の中の「contrast limited」が指すCLAHEの部分です。局所的な平坦化は、CDFが取り得る異なる値が非常に少ない平坦な領域でノイズを過剰に増幅することがあります。クリップ制限は、いずれの単一のビンがどれほど積極的に再分配され得るかを上限で抑え、これによりノイズの増幅を防ぎつつ、重要な箇所でのコントラストストレッチは依然として可能にします。10 前後の値が妥当な出発点です。より大きな値はCLAHEをより強く働かせますが、より目立つノイズという代償を伴い、より小さな値は効果を穏やかにします。

CLAHEは グローバル なhisteqよりも処理コストが高いですが、明るさが不均一に分布したシーン、つまりほとんどの実世界のシーンでは、よりclean な結果を生み出します。

5.19.3. ガンマ、コントラスト、明るさ

ヒストグラム平坦化は、データ駆動で明るさを再マッピングする方法です。データに依存しない 方法は、いくつかの調整しやすいつまみでパラメータ化された、選択したカーブを適用することです。gamma() は3つを提供します:

img.gamma(gamma=1.0, contrast=1.0, brightness=0.0)

各パラメータは、すべてのピクセルに1つの特定の変換を適用します:

gamma は各ピクセルの値をべき関数 output = input ** (1 / gamma) に通します。標準的な意味は次のとおりです。1.0 より大きい値は画像を 明るく し、中間調を持ち上げます(古典的な「モニターガンマ」補正)。1.0 より小さい値は画像を 暗く します。このパラメータは非線形です。黒点と白点を保持し、その間の分布だけを再形成します。これは、既存の極値をつぶすことなく影やハイライト領域のディテールを回復することが目的の場合に正しい挙動です。

contrast は各ピクセルを中間グレー点を中心とした単純な乗算に通します。1.0 より大きい値はコントラストを増加させ(暗い部分はより暗く、明るい部分はより明るく、中間グレーは変わらず)、1.0 より小さい値はコントラストを低減します。

brightness はすべてのピクセル値に定数を加えます。正の値は明るくし、負の値は暗くします。このシフトは 一様 で、何も保持されません。これはアプリケーションがそれ単独で求めることはまれですが、結果を再び中心に寄せるコントラストパスとよく組み合わさります。

3つのパラメータは組み合わせられます。1回の gamma() 呼び出しで、ガンマカーブ、続いてコントラストの乗算、続いて明るさのシフトを、すべて1回のパスで適用できます。順序はガンマが最初、次にコントラスト、次に明るさで、これは3つすべてが非デフォルトのときに最も直感的な結果を与える順序と一致します。

5.19.4. オートホワイトバランス

階調補正のカラー系統はまず オートホワイトバランス から始まります。センサーのISPが撮像パイプラインの一部として実行するのと同じ仕組み(平均的なグレー色のパッチが実際のグレーとして読み取られるように、赤、緑、青の各チャンネルの相対的なゲインを調整するもの)は、完成した Image に対する撮影後の操作としても利用できます:

img.awb()

デフォルトでは gray-world アルゴリズムを使用します。画像全体の平均カラーが中立的なグレーであると仮定し、それがそうなるようチャンネルごとのゲインを調整します。代替の max=True 形式は white-patch アルゴリズムを使用します。最も明るいピクセルが中立的な白であると仮定し、それがそうなるようにゲインを調整します。どちらもRGB565と生のBayerで機能します。どちらもグレースケール(バランスを取るカラーがない)やYUV(これらのアルゴリズムが扱うカラー表現ではない)では機能しません。

ISPのオートホワイトバランスではなく撮影後の形式に頼るべき場合は、ISPの選択が特定のシーンにうまく合わなかったとき、アプリケーションが異なる条件で撮影された参照フレームをディスクから読み込んでいるとき、あるいはカラーの判断が重要で、アプリケーションが独自のアルゴリズム選択で再実行したいときです。

5.19.5. カラー補正行列

画像に必要なカラー補正が、ホワイトバランスが与えるチャンネルごとのスケーリングではなく、より一般的な チャンネルミキシング である場合、頼るべき操作は カラー補正行列 です。ccm() メソッドは、各ピクセルの (r, g, b) ベクトルに乗算して新しい (r, g, b) ベクトルを生成する3×3(オフセット付きの場合は3×4)の行列を適用します:

img.ccm([[1.1, -0.05, -0.05],
        [-0.05, 1.1, -0.05],
        [-0.05, -0.05, 1.1]])

この行列により、アプリケーションはカラーチャンネル間のクロストークを補正できます。例えば赤センサーの応答にいくらかの緑色の光が含まれている場合、行列は緑チャンネルの一部を赤の出力から差し引いて補償することができます。チャンネルごとのオフセットと組み合わせれば、3×4形式により、アプリケーションは各チャンネルのゼロ点を再設定することもできます。

ISPパイプライン の資料では、カラー補正行列の 理由 を扱っています。Image に対する撮影後の形式は、まったく同じ操作を後から適用したものにすぎません。