ヒストグラム均一化と、2値化の検討
ヒストグラムの均一化
画像濃度のヒストグラムを均一化することで、画像の濃度を調整します。
画像の濃度が幅広く分布し、コントラストが大きくなった画像になります。
計算方法を、いろいろ検索をしたのですが、計算が簡単な、基本的な画像処理手法について
にあるものを使用しました。
w = INT( ( v(u) - vmin ) x ( L - 1 ) / ( 1 - vmin ) )
w: 変換後の画素値、
v(u): 変換前画素値uに対する累積度数÷画面の総画素数
vmin:
v(u)の最小値
L: 階調数(256)
ヒストグラムの作成と、グラフ表示
此処では、カラーをグレーに変換した配列データーをしようします。
配列データーは、ファイルをオープンした時に、作成しておきます。
HistMat[]が最初のヒストグラム、RuisMat[]が累積度数です。
//****************************** // グレイヒストグラム表示 //****************************** procedure TForm1.HistogramChart; // ヒストグラムの作成と表示 var I , j: Integer; begin for I := 0 to 255 do HistMat[I] := 0; for I := 0 to GHeight - 1 do for J := 0 to GWidth - 1 do inc(HistMat[GrayMat[I, J]]); I := 0; for J := 0 to 255 do begin I := I + HistMat[J]; RuisMat[J] := I; end; Series1.clear; for I := 0 to 255 do begin Series1.Add(HistMat[I]); end; end;
ヒストグラムの均一化実行と表示
//******************************************************* // ヒストグラム平均化 // w = INT( ( v(u) - vmin ) x ( L - 1 ) / ( 1 - vmin ) ) // // w: 変換後の画素値、 // v(u): 変換前画素値uに対する累積度数÷画面の総画素数 // vmin: v(u)の最小値 // L: 階調数(256) // INT(): 整数化関数 // //******************************************************* procedure TForm1.HistoavreageBtnClick(Sender: TObject); var HH, WW : integer; PBa : PByteArray; DW : Integer; ALLdot: Integer; Vmin : double; // 最小値 begin ALLdot := Gheight * GWidth; // ゼロ以外の最小値 Vmin := 0; for HH := 0 to 255 do begin if RuisMat[HH] > 0 then begin Vmin := RuisMat[HH] / ALLdot; break; end; end; // ヒストグラム平均化 for HH := 0 to Gheight - 1 do for WW := 0 to GWidth - 1 do begin GOSAMat[HH, WW] := Round((RuisMat[GrayMat[HH, WW]] / ALLdot - Vmin) * 255 / (1 - vmin)); if GOSAMat[HH, WW] < 0 then GOSAMat[HH, WW] := 0; end; // 平均化ご画像表示 OutputBitmap.Assign(nil); OutputBitmap.PixelFormat := pf24bit; OutputBitmap.Width := GWidth; OutputBitmap.Height := GHeight; for HH := 0 to GHeight - 1 do begin PBa := OutputBitmap.ScanLine[HH]; for WW := 0 to GWidth - 1 do begin DW := WW * 3; PBa[DW ] := GOSAMat[HH, WW]; PBa[DW + 1] := GOSAMat[HH, WW]; PBa[DW + 2] := GOSAMat[HH, WW]; end; end; Image1.Canvas.StretchDraw(VRect, OutputBitmap); // 出力枠に変倍出力 for HH := 0 to 255 do HistMat[HH] := 0; for HH := 0 to GHeight - 1 do for WW := 0 to GWidth - 1 do inc(HistMat[GOSAMat[HH, WW]]); Series1.clear; for HH := 0 to 255 do begin Series1.Add(HistMat[HH]); end; end;
カラー画像の検討
カラーの場合、RGB毎に、ヒストグラムの均一化を行うと、カラーバランスが崩れて、画像が乱れてしまいしまいます。
そこで、画像の輝度値は、グレーの輝度値に沿って、元のRGBの割合を崩さないようにして新しい値とするようにしました。
もし、RGBのどれかが、255を超える場合は、最大値を255として、他の色は、元の割合になるように補正し、255を越えないようにします。
上の画像の場合は、それなりにコントラストが付いた画像になりましたが、画像によっては、均一化した結果、悪くなってしまう場合もあります。
それぞれ右側が均一化後の画像ですが、黒くなったり、明るくなりすぎています。
カラーによる問題かと考え、グレー画像でも行ってみましたが、同じ様な傾向にあるようです。
コントラストの調整は、微調整の出来る、変換曲線の指定による補正の方が良い結果が得られるようです。
2値化の検討
パソコンの記憶容量が大きくなり、画像を2値化するのは、画像を利用した測定ぐらいに限られるようになりました。
以外に、簡単なことなのですが、自動測定を行う場合、2値化も自動的に行いたいので、その方法について少し検討してみました。
閾値の指定
単純にシキイ値を指定して2値化をしています。
シキイ値を固定していると画像によっては、非常に悪い画像になる事があります。
閾値127の画像は結構良い画像となっていますが、たまたま取り上げたサンプルが良かったのかと思います。
比率の指定
黒50パーセントは、ヒストグラムを作成し、ヒストグラムの輝度値小さいほうの値と大きい方の値で、小さいほうの値の合計が全体の値に対して指定されたパーセントになるように閾値を設定します。
//********************************* // 黒パーセント指定2値化 //********************************* procedure TForm1.PercentBtnClick(Sender: TObject); var threshold : Integer; AllAdd : Integer; Dadd : Integer; Percent : Double; Percent100 : Double; ch : Integer; HH, WW : Integer; PBa : PByteArray; DW : Integer; begin val(PercentEdit.Text, Percent, Ch); if ch <> 0 then begin Application.MessageBox('パーセントの値に間違いがあります', '注意', 0); exit; end; Percent100 := Percent / 100; // AllAdd := 0; Dadd := 0; threshold := 0; // AllAddは画像縦ドット数×横ドット数と同じになります AllAdd := GWidth * GHeight; // for HH := 0 to 255 do AllAdd := AllAdd + HistMat[HH]; // 指定%と同じが越えた位置を検出し閾値を決定します for WW := 0 to 255 do begin Dadd := Dadd + HistMat[WW]; if Dadd / AllAdd >= Percent100 then begin threshold := WW; break; end; end; // 閾値により2値化します OutputBitmap.Assign(nil); OutputBitmap.PixelFormat := pf8bit; OutputBitmap.Width := GWidth; OutputBitmap.Height := GHeight; for HH := 0 to GHeight - 1 do begin PBa := OutputBitmap.ScanLine[HH]; for WW := 0 to GWidth - 1 do begin DW := WW; if GrayMat[HH, WW] >= threshold Then PBa[DW] := $FF else PBa[DW] := $00; end; end; Image1.Canvas.StretchDraw(VRect, OutputBitmap); // 出力枠に変倍出力 end;
判別分析法は、閾値を境にして黒側の分散、白側の分散を求め、分離度が最大になる点に閾値を設定する方法ですが、詳しくは、
イメージソリューションを参照して下さい。
誤差拡散法は、測定とは関係ないのですが、2値化するとハーフトーンの再現が出来ないので、ドットにしてハーフトーンの再現が出来る様にしたものです。
画像処理 誤差拡散法で検索すれば沢山見つかります。