5.18. ヒストグラムと統計

画像のピクセルを変更する操作と並んで、Image クラスにはそれらを測定する一連のメソッドが備わっています。ピクセル値の分布を要約し、平均輝度と中央値を返し、暗いピクセルと明るいピクセルの最適な区切り点を見つけ、カラーチャンネルの広がりを報告します。これらの測定値は2つの方法でアプリケーションに役立ちます。1つは、どのしきい値を使うか、どのゲインを設定するか、シーンの階調プロファイルがどのように見えるかを決めるコードへの入力として。もう1つは、「シーンは十分に明るいか?」といった診断信号として。これにより、アプリケーションは特定のピクセルについて判断することなく対処できます。

ほぼすべての測定の出発点はヒストグラムです。

5.18.1. ヒストグラム

画像のヒストグラムとは、可能な各輝度値を持つピクセルがいくつあるかを数えたものです。グレースケール画像の場合、これは 0 から 255 までの値でインデックス付けされたカウントのリストです。カラー画像の場合は、そのようなリストが3つ(チャンネルごとに1つ)になります。

get_histogram() はそれを計算します。

h = img.get_histogram()

返されるオブジェクトは histogram 結果で、チャンネルごとのビンのリストと、それらに対するいくつかの高レベルなクエリを公開します。ビンのカウントは合計が 1.0 になるように正規化されています。つまり、ヒストグラムは絶対的なピクセル数ではなく分布のプロファイルを記述するため、異なるサイズの画像間でも測定値を比較できます。

グレースケール画像の場合、ヒストグラムはビンのチャンネルを1つ持ち、h.bins()(または同等の h[0])として利用できます。RGB565画像の場合、ヒストグラムは二値しきい値処理のページで紹介したLABカラー空間で計算され、3つのビンチャンネルが h.l_bins()h.a_bins()h.b_bins()(または h[0]h[1]h[2])として利用できます。LABはしきい値処理および追跡メソッドが使うのと同じ選択であり、ヒストグラムはどの空間でカラーが測定されているかについてしきい値と一致します。

5.18.2. ビンとビン数

デフォルトのヒストグラムは、可能なピクセル値ごとに1つのビンを持ちます。8ビットチャンネルなら 256 ビンです。これはアプリケーションが必要とするよりも細かい解像度である場合があります。分布のおおまかなプロファイルだけを気にする分類器なら、より少ないビン数(32 あるいは 8 ビン)の方が適しているかもしれません。これは実行が速くなり、ノイズに対してよりクリーンな結果を生み出します。bins キーワード(およびカラー用のチャンネルごとの l_binsa_binsb_bins)でその数を設定します。

h = img.get_histogram(bins=32)

ROIとしきい値のスコープは、他のすべての測定メソッドと同じように機能します。roi を渡してヒストグラムをピクセルの矩形に限定し、thresholds リストを渡してそれらの範囲に一致するピクセルだけを含めます。しきい値の形式は、「一致するピクセルだけのヒストグラムを計算する」を1回の呼び出しで行えるようにするものであり、すでに検出された領域のテクスチャを、自分でピクセルを走査することなく特徴付けたい場合の一般的なパターンです。

輝度範囲0から255にわたって棒の列 として描かれたグレースケールヒスト グラム。分布には2つのピークがあり、 小さい暗いピークと大きい明るいピー クが明確な谷で分けられている。3本 の垂直線が重ねられている。谷の中の Otsuしきい値、大きい明るいピーク 寄りにずれた平均、そして累積ピクセ ル数が半分に達するさらに右の中央値。

3つの要約測定値を重ねたグレースケールヒストグラム。Otsuのしきい値(暗いクラスタと明るいクラスタを最もよく分割する区切り点)、平均、そして中央値。各測定値は同じ分布について異なることを示しています。

5.18.3. 統計

ヒストグラムはすべての値の出現頻度の記述です。統計はそこから導かれる数値的な要約です。get_statistics() が返す statistics オブジェクトは標準的なセットを備えています。

  • mean -- ピクセル値の算術平均。

  • median -- 半数のピクセルがそれより下にある値。

  • mode -- 最も多く出現する単一の値。

  • stdev -- 標準偏差。平均周りの広がりの尺度。

  • minmax -- 存在する最も明るいピクセル値と最も暗いピクセル値。

  • lquq -- 下側および上側の四分位の区切り点。

RGB565画像の場合、チャンネルごとの形式(l_meana_medianb_mode など)が同じ測定値をチャンネルごとに提供します。

これらの数値のほとんどは特定の文脈で登場します。meanstdev を合わせるとノイズの推定値が得られます。一様であるべきシーンは小さい stdev を持ち、ノイズの多いセンサーは同じシーンに大きい stdev を与えます。minmax は画像のコントラストを示します。両者が近いほどシーンは平坦で、離れているほどアルゴリズムが扱えるダイナミックレンジが広くなります。median は分布に外れ値があるときのロバストな中心です(少数の非常に明るいピクセルは、平均を引っ張るようには中央値を引っ張りません)。mode は最も多く出現する単一の値で、背景がほとんどのピクセルを覆う画像の背景レベルを見つけるのに役立ちます。

get_statistics() は内部でヒストグラムのパスを実行してからそれを要約します。以前に計算したヒストグラムと同じ thresholds および roi 引数を渡すと、同じピクセルの集合に対する統計が得られます。

5.18.4. パーセンタイルとCDF参照

histogram オブジェクトは get_percentile() メソッドを公開します。これは割合をピクセル値に変換します。つまり、要求された割合のピクセルがそれより下にある値です。h.get_percentile(0.5) は中央値です。h.get_percentile(0.05)h.get_percentile(0.95) を合わせると、下位および上位5%を外れ値として無視するロバストなmin/maxが得られます。

これは、少数の散発的な明るいまたは暗いピクセルが答えを歪めることを許さずに、ピクセル値の範囲を特徴付けたいときにアプリケーションが使う形式です。5パーセンタイルと95パーセンタイルから得られるロバストなmin/maxは、コントラストストレッチのパス(階調補正で扱うピクセルごとの再マッピング)への自然な入力でもあります。

5.18.5. Otsuの手法

ヒストグラムはそれ自体で取り上げる価値のある別の問いにも答えます。ピクセルが「暗い」クラスタと「明るい」クラスタに分かれる画像が与えられたとき、それらの間の区切り点はどこか? しきい値処理のページではすでにそのメカニズムをその結果(アプリケーションが binary() に渡せる単一のグローバルしきい値)で名付けましたが、どのようにについては先送りしていました。その方法がOtsuの手法であり、ヒストグラム上に存在します。

直感的には、明確な前景と背景を持つ画像は、その輝度ヒストグラムに2つのクラスタを持ち、それらの間に谷があります。しきい値を設定すべき正しい場所は谷の底、つまり2つのクラスタが最もよく分離される値です。Otsuの手法は可能なすべての区切り点を探索し、クラスタ内分散が最小になる(これはクラスタ間分散が最大になると言うのと同じ)ものを選びます。その結果が、その特定の画像の分布に対する最適な二値分割です。

histogram オブジェクトは get_threshold を通じてOtsuを公開します。

h = img.get_histogram()
t = h.get_threshold()

返される threshold オブジェクトには、選択された区切り点を運ぶ value(グレースケール用)または l_value / a_value / b_value(カラー用)属性があります。その結果をそのまま binary() に戻すと、区切り点が画像自身によって選ばれる自己調整型のグローバルしきい値が得られます。

img.binary([(t.value, 255)])

このパターンは、フィルタベースの適応的しきい値が解決する不均一な照明の問題を解決するものではありません。それが解決するのは、グローバルしきい値処理がすでに正しいアプローチである場合の「どの値で切るべきか?」という問いです。前景と背景の区別が明確なシーンでは、Otsuが選ぶ値は通常、人間が目で選ぶ値と数単位以内に収まります。

5.18.6. 差分画像での計算

get_histogram()get_statistics() に関する有用な詳細。どちらも別の Image を取る difference キーワードを受け付け、ソースとその画像のピクセルごとの差分のヒストグラム(または統計)を、別個の差分画像を割り当てることなく計算します。これは、測定されることだけが目的の画像を生成するための明示的な difference() 呼び出しのコストを払わずに、「参照フレーム以降シーンはどれだけ変化したか?」を尋ねる安価な方法です。継続的に実行される動き検出スクリプトでは、この節約が積み重なります。