輪郭抽出
ここで使用されているサンプル画像は SIDBA (Standard Image Data-Base) で検索すると、幾つかのサイトが見つかるので、その中からダウンロードしたものです。
輪郭抽出は、画像データーの濃度変化を、微分して変化の大きさに応じて抽出するものですが、その理論、詳しいアルゴリズムは、インターネットで、画像処理、或いは、画像処理入門で検索すると見つかりますのでそれを参照して下さい。
計算の手順は意外と単純です。
ここの例は、Delphiでプログラミングした場合の例で、何も新しいものはありません。
上図9個の値の真ん中にある位置を計算をする座標にあわせて、その場所を含み、周囲8箇所の座標の値と、マスクの値の積を行い全て(9箇所)加算します。
それを、X,
Y (X微分、Y微分)について行い、その二つの値から、その座標の微分値( sqrt(X*X + Y*Y) )を求めます。
単純に計算すると、画像の幅が500、高さ400とすると、計算出来るのは 幅498、高さ398となり、周囲一列は計算しません。
(全てを計算する為に、データーの無い部分に仮の値を入れる方法もあります。)
通常と、Robertsの場合、ゼロの部分が多いので、ゼロの部分は計算しないようにプログラムを組んでも良いのですが、計算ルーチンを簡単にするため無条件に全て計算しています。
// 一次微分 オペレーター cx0 : array[0..8] of integer = ( 0, 0, 0, // 一次微分 Gradient 通常の微分 オペレーター 0, 1,-1, 0, 0, 0); cy0 : array[0..8] of integer = ( 0, 0, 0, 0, 1, 0, 0,-1, 0); cx1 : array[0..8] of integer = ( 0, 0, 0, // 一次微分 Gradient Roberts オペレーター 0, 1, 0, 0, 0,-1); cy1 : array[0..8] of integer = ( 0, 0, 0, 0, 0, 1, 0,-1, 0); cx2 : array[0..8] of integer = (-1,-2,-1, // 一次微分 Gradient Soble オペレーター 0, 0, 0, 1, 2, 1); cy2 : array[0..8] of integer = (-1, 0, 1, -2, 0, 2, -1, 0, 1); // 3 X 3 データー取り出し用 中心座標加算値 dy : array[0..8] of integer = (-1,-1,-1, 0, 0, 0, 1, 1, 1); dx : array[0..8] of integer = (-1, 0, 1, -1, 0, 1, -1, 0, 1); --------------------------------------------------------------------------- for i := 1 to BHeight - 2 do for j := 1 to BWidth - 2 do begin for K := 0 to 8 do // グレーデーター取り出し d[k] := Graydata[i + dy[k], j + dx[k]]; xx := 0; yy := 0; case Dvt1 of // オペレーターの選択 1: for k := 0 to 8 do begin xx := xx + cx0[k] * d[k]; yy := yy + cy0[k] * d[k]; end; 2: for k := 0 to 8 do begin xx := xx + cx1[k] * d[k]; yy := yy + cy1[k] * d[k]; end; else for k := 0 to 8 do begin xx := xx + cx2[k] * d[k]; yy := yy + cy2[k] * d[k]; end; end; zz := ampf * sqrt(xx * xx + yy * yy); dat := round(zz); if dat > HIGH then dat := HIGH; Image_out1[ i, j] := byte(dat); end;
一次微分のサンプル画像です。
二次微分は、単純に、ターゲット位置を含みその周囲の値の積の総和を計算し、ターゲット位置のデーターとするだけです。
計算結果は、プラス部分と、マイナス部分になり、本来の変化点とはずれた位置になります。
プラスと、マイナスの中間点が、実際の変化点中心となりますが、この位置を特定することは困難です。
二次微分サンプル マイナスの符号をとり絶対値として表示しているため、線がダブって見えます。
プラス側だけ表示したサンプルです。
画像はすっきりしますが、実際の画像とは、僅かに大きさが変化します。
Prewitt は8方向のマスクの計算を行い、その中で一番大きいマスクの値を採用します。
一番変化率の高い方向の値をその座標のデーターとします。
Prewittのサンプル画像です。
画像グレイ配列データーより、データーを取り出すとき、微分用マスクの配列と、ターゲット座標に対して、プラス、マイナスして取り出す値の配列を同じ添字にする事で、For
文により簡単に計算する事が出来ます。
細線化
微分により画像の変化点を抽出すると、画像濃度の変化の具合で線として欲しい、白 又は、黒の部分の幅が広くなってしまいます。
計測に使用するのには、あまり良くありません。
そこで、細線化処理をして、線の中心点を求めます。
これには、色々なアルゴリズムが研究されているのですが、此処では、Hilditch の方法について、プログラムを取り上げてあります。
ダウンロードして試してみて下さい。
Hilditchの画像サンプルです。
ファイルから画像データーを入力しますが、プログラムは、JPEGと、24ビットビットマップに対応しています。
計算は、表示は24ビットビットマップを利用して行いますが、ビット数が違う場合は、変換をします。
又、 Delphi は色々なフォーマットに対応していますので、その場合の変換方法は、インターネットで検索して下さい。
次の例は、ビットマップのフォーマットを24ビットに変換するする場合です。
var BitmapD, InputBitmap: TImage; procedure TMainF.FileOpenBtnClick(Sender: TObject); begin if OpenDialog1.Execute then begin // ファイルが指定されたら BitmapD := Tbitmap.Create; // ビットマップイメージの生成 BitmapD.LoadFromFile(OpenDialog1.FileName); // ビットマップファイルの読み込み end esle exit; InputBitmap := TBitmap.Create; // ビットマップ作成 InputBitmap.HandleType := bmDIB; // ビットマップの形式をDIBに設定 InputBitmap.PixelFormat := pf24bit; // DIBの形式を24ビットに設定 InputBitmap.Width := BitmapD.Width; InputBitmap.Height := BitmapD.Height; InputBitmap.Canvas.Draw(0, 0, BitmapD); // InputBitmap.Canvas にコピー(作画) 非表示 BitmapD.Free; // ビットマップの破棄 end;