目的
暗く写ってしまった画像や明るく写ってしまった画像の明るさを補正する処理に濃度変換がある.ここでは,画素値の分布を視覚化することができる濃度ヒストグラムとBGRヒストグラムを求め,明るさを補正する処理を学ぶ.
説明
濃度変換と濃度ヒストグラム
例えば暗い場所でディジタルカメラを使用して撮影した画像は全体的に暗くなる.このような画像では濃度分布が暗い領域に集中することになる.このように濃度分布に偏りがある画像を偏りがないように変換できれば,暗く写ってしまった画像を明るく補正したり,明るく写ってしまった画像を暗く補正することができる.このような処理を濃度変換と呼ぶ.
濃度変換を行う前に濃度の分布がどのようになっているかを調べてみよう.画像全体の濃度値の分布を知りたければ,各濃度値をもつ画素の数を数え,横軸に濃度値,縦軸に画素数をとったグラフを描けばよい.このようなグラフを濃度ヒストグラムと呼ぶ.
ヒストグラムの描画
濃度ヒストグラム
以下の8bit256階調グレースケール画像の濃度ヒストグラムを描画してみよう.
20行目でグレースケール画像を読み込み,25行目で濃度ヒストグラムを描画している.また,32行目のようにキーワード引数densityにTrueを指定すると,グラフの縦軸が画素数ではなく,全体の画素数に対する比率となる.実行すると以下のように濃度ヒストグラムが表示される.
BGRヒストグラム
カラー画像では画素値がBGRによって表現されていた.カラー画像の画素値の分布を知りたければ,BGRの各値に対してヒストグラムを求めればよい.これをBGRヒストグラムと呼ぶ.以下の24bitカラー画像のBGRヒストグラムを描画してみよう.
25, 32, 39行目でblue, green, redのそれぞれに対してヒストグラムを描画している.また,46, 53, 60行目で縦軸を比率としてBGRヒストグラムを描画している.実行すると以下のようにBGRヒストグラムが表示される.
ヒストグラムの計算
以上の例ではヒストグラムを単に描画した.ヒストグラムの値を処理に使用したいときには,ヒストグラムの値を計算し,グラフとして描画する必要がある.ここでは,ヒストグラムの値を計算してみよう.
numpyモジュールのbincount関数
23行目のようにnumpyモジュールのbincount関数を使用すれば,256階調グレースケール画像の各濃度値に対して画素数を求めることができる.24行目で求めた画素数を表示すると以下のように表示され,各濃度値に対して画素数が求められていることがわかる.
28行目でグラフの横軸のデータを作り,29行目でヒストグラムを描画している.実行すると以下のように濃度ヒストグラムが表示される.
24bitカラー画像に対してBGRヒストグラムの値を求めてみよう.
22行目から24行目でBGRの各ヒストグラムの値を求め,25行目から27行目で表示している.実行すると以下のように表示され,BGRの各値に対して画素数が求められていることがわかる.
35, 43, 51行目でBGRヒストグラムを描画している.実行すると以下のようにBGRヒストグラムが表示される.
numpyモジュールのhistogram関数
numpyモジュールのhistogram関数を使用してもヒストグラム値を求めることができる.
23行目のように記述すると,濃度ヒストグラムの値を求めることができる.また,24行目のようにキーワード引数densityにTrueを指定すると,濃度ヒストグラムの値を比率として求めることができる.26-28行目でそれらの値とヒストグラムのビンの値を表示している.実行すると以下のように表示される.
34行目と41行目で濃度ヒストグラムを描画している.実行すると以下のように濃度ヒストグラムが表示される.
24bitカラー画像に対してBGRヒストグラムの値を求めるには以下のようにすればよい.
22行目から27行目でBGRヒストグラムの値を求め,29行目から35行目で表示している.
また,以下のようにBGRヒストグラムが表示される.
線形濃度変換
グレースケール画像
以下のような暗い所で撮影した8bitグレースケール画像の濃度ヒストグラムは濃度値の小さい領域に分布していることがわかる.
このように濃度値がある範囲に集中している画像をコントラストの悪い画像と言う.コントラストの悪い画像では濃度値が\(x_0\)から\(x_1\)の間に集中していて,\(x_{min}\)から\(x_0\)の範囲・\(x_1\)から\(x_{max}\)の範囲がほとんど使われていない.このような画像を,濃度ヒストグラムが濃度値全体に広がるように変換できれば,暗く写ってしまった画像を明るく,あるいは明るく写ってしまった画像を暗く補正することができるだろう.
では,濃度値が\(x_0\)から\(x_1\)の範囲に集中している画像を濃度値全体\(x_{min}\)から\(x_{max}\)まで)に分布するように線形に変換してみよう.横軸に変換前の濃度値を,縦軸に変換後の濃度値をとって入出力の関係を図に表すと,直線で表せるような変換を線形濃度変換と呼ぶ.
図より,入出力の関係は3本の直線で表せる.この3本の直線を場合分けしてそれぞれ求めると,以下のような変換式が得られる.$$ x^{\prime} = \begin{cases} x_{min} & (x_{min} \leq x < x_0) \\ \frac{x_{max}-x_{min}}{x_{1}-x_{0}}(x-x_0)+x_{min} & (x_0 \leq x \leq x_1) \\ x_{max} & (x_{1} < x \leq x_{max}) \end{cases}$$
では,暗い所で撮影した8bitグレースケール画像を線形濃度変換し,明るさを補正してみよう.
21行目でグレースケール画像を読み込み,22行目で濃度ヒストグラムを求めている.24,25行目で濃度値が集中している範囲を10から70とし,8bitグレースケール画像を対象としているため26,27行目で濃度値の範囲を0から255としている.28行目から32行目で線形濃度変換し,33行目で変換後の画像の濃度ヒストグラムを求めている.実行すると以下のように表示され,明るさが補正できていることがわかる.
また,入力画像の濃度ヒストグラムは濃度値の小さい領域に分布しているが,線形濃度変換した後の画像の濃度ヒストグラムは濃度値全体に分布していることがわかる.
カラー画像
カラー画像を線形濃度変換するには,BGRの各値に対して変換を施せばよい.暗い所で撮影した24bitカラー画像を線形濃度変換し,明るさを補正してみよう.
21行目でカラー画像を読み込み,22行目から24行目でBGRヒストグラムを求めている.26行目から34行目で線形濃度変換を行い,35行目から37行目で変換後の画像のBGRヒストグラムを求めている.実行すると以下のように表示され,明るさが補正されていることがわかる.
また,入力画像のBGRヒストグラムは暗い領域に分布しているが,線形濃度変換した後の画像のBGRヒストグラムはBGR値全体に分布していることがわかる.
線形濃度変換(画素値が集中している範囲を推定)
以上の例では,入力画像のヒストグラムから画素値が集中している範囲を調べて指定していた.ここでは簡単な方法で画素値が集中している範囲を推定し,線形濃度変換してみよう.
グレースケール画像
濃度値が集中している範囲を完全に求めることは難しいため,ここでは簡単な方法を考えることにしよう.グレースケール画像の濃度ヒストグラムを求め,左から右へ(濃度値をだんだん大きくして)濃度ヒストグラムの画素数を参照し,その画素数があるしきい値を越えたとき,その濃度値を\(x_0\)とする.逆に,右から左へ(濃度値をだんだん小さくして)濃度ヒストグラムの画素数を参照し,その画素数があるしきい値を越えたとき,その濃度値を\(x_1\)とする.しきい値を自動で決めるのは難しいため,指定することになる.解像度がわかっているなら固定の値とし,解像度がわからない場合には全画素数に対する相対的な値とすればよい.
24行目でしきい値を指定し,25行目から29行目で\(x_0\)を求め,31行目から34行目で\(x_1\)を求めている.35,36行目で求めた値を表示している.実行すると以下のように表示され,濃度値が集中している範囲が5から73と推定されていることがわかる.
線形濃度変換し,明るさが補正された画像と,入出力画像の濃度ヒストグラムは以下のようになる.
カラー画像
カラー画像の場合は,BGRそれぞれについて画素値が集中している範囲を求め,それぞれ線形濃度変換すればよい.
9行目から20行目でヒストグラムとしきい値から画素値が集中している範囲を推定する関数を定義し,51行目から59行目でBGRそれぞれについて画素値が集中している範囲を推定し,表示している.実行すると以下のように表示され,BGRの各値が集中している範囲が求められていることがわかる.
23行目から31行目で線形濃度変換する関数を定義し,62行目から64行目で関数を呼び出し,BGRそれぞれに対して線形濃度変換している.実行すると以下のように表示され,明るさが補正されていることがわかる.
ヒストグラム平坦化
明るさを補正する際によく使用される処理には線形濃度変換の他にヒストグラム平坦化がある.
グレースケール画像
8bitグレースケール画像に対してヒストグラム平坦化を行ってみよう.
21行目でグレースケール画像を読み込み,22行目で濃度ヒストグラムを求めている.24行目でOpenCVのequalizeHist関数を呼び出すことでヒストグラム平坦化を行っている.25行目で変換後の画像の濃度ヒストグラムを求めている.実行すると以下のように表示され,明るさが補正できていることが確認できる.
入出力画像の濃度ヒストグラムは以下のようになり,出力画像のヒストグラムは平坦になっていないことがわかる.
ヒストグラム平坦化ではどのような処理が行われているかを確認してみよう.
23行目で入力画像の濃度ヒストグラムの累積分布を求め,24行目でグラフとして描画するために大きさを正規化している.同様に28行目で出力画像の濃度ヒストグラムの累積分布を求め,29行目で大きさを正規化している.それらを36行目と45行目で描画している.実行すると以下のように表示され,ヒストグラム平坦化した画像では,濃度ヒストグラムの累積分布が直線となっていることがわかる.ヒストグラムが平坦であれば累積分布の傾きは一定となることから,実質的にはヒストグラムが平坦化された処理と同等の処理がなされていることがわかる.
カラー画像
カラー画像に対してヒストグラム平坦化を行ってみよう.
32行目から35行目でBGRそれぞれに対してヒストグラム平坦化を行っている.22行目から38行目で,変換前の画像のBGRヒストグラムを求め,その累積分布を求めている.36行目から44行目で,変換後の画像に対してもBGRヒストグラムとその累積分布を求めている.実行すると以下の様に表示され,BGRそそれぞれに対してヒストグラムが平坦化され,明るさが補正されていることがわかる.
課題
課題0
グレースケール画像を読み込み,濃度ヒストグラムを表示せよ.
課題1
カラー画像を読み込み,BGRヒストグラムを表示せよ.
課題2
グレースケール画像を読み込み,numpyモジュールのbincount関数により濃度ヒストグラムを求め,表示せよ.
課題3
カラー画像を読み込み,numpyモジュールのbincount関数によりBGRヒストグラムを求め,表示せよ.
課題4
グレースケール画像を読み込み,numpyモジュールのhistogram関数により濃度ヒストグラムを求め,表示せよ.
課題5
カラー画像を読み込み,numpyモジュールのhistogram関数によりBGRヒストグラムを求め,表示せよ.
課題6
グレースケール画像を読み込み,線形濃度変換せよ.
課題7
カラー画像を読み込み,線形濃度変換せよ.
課題8
グレースケール画像を読み込み,ヒストグラム平坦化せよ.
課題9
カラー画像を読み込み,ヒストグラム平坦化せよ.