ソーベルフィルタを写真画像に適用させ境界(エッジ)検出(VCL) ~Delphiソースコード集
(参考)バイキュービック法(bicubic)で拡大縮小する(VCL)
(参考)バイキュービック法(bicubic)で拡大縮小する(FMX)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(VCL)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(FMX)
ソーベルフィルタを使用する為のファイルの準備
本ページの下部のソースコードをコピーして「SobelFilter.pas」ファイルを作成し、 プロジェクトフォルダ内に入れる。ソースコードの記述
プロジェクトを新規作成(VCLアプリケーション)し、フォーム(Form1)にTImageを2個、TButtonを1個配置する。Image1のPictureプロパティから、ソーベルフィルタを適用したい画像をロードしておく。
TButton1をダブルクリックして、以下ソースコードを記述する。
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.Imaging.jpeg; type TForm1 = class(TForm) Button1: TButton; Image1: TImage; Image2: TImage; procedure Button1Click(Sender: TObject); private { Private 宣言 } public { Public 宣言 } end; var Form1: TForm1; implementation uses SobelFilter; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var source,dest:TBitmap; begin source:=TBitmap.Create; source.Assign(Image1.Picture.Graphic); source.PixelFormat:=pf24bit; dest:=TBitmap.Create; dest.PixelFormat:=pf24bit; //ノイズ除去の為、ガウシアン(ぼかし)フィルタを適用 MamGausianFilter(source,dest); source.Assign(dest); //ソーベル(境界[エッジ])フィルタ MamSobelFilter(source,dest); //ソーベルフィルタを適用した画像を表示 Image2.Picture.Bitmap.Assign(dest); dest.Free; source.Free; end; end.
実行する
実行ボタンを押して実行します。(デバッグ実行でもOK)Button1をクリックすると、Image1画像にガウシアンフィルタとソーベルフィルタを適用した画像をImage2に表示します。
「SobelFilter.pas」ファイルのソースコード
unit SobelFilter; interface uses Vcl.Graphics,System.Math; Type TMn=array of array of double; TRRGB=record B,G,R:Extended; end; TRGB =record B,G,R:byte; end; TRGBArr=array[0..32767] of TRGB; PRGBArr=^TRGBArr; TRGBArrArr=array[0..32767] of PRGBArr; TGauss=array of array of double; const //ガウシアン3x3フィルタ係数配列 gauss3:array[0..2]of array[0..2]of double= ( (1,2,1),(2,4,2),(1,2,1) ); //ソーベルフィルタ係数配列 Sobelh:array[0..2]of array[0..2]of double= ( (-1,0,1),(-2,0,2),(-1,0,1) ); Sobelv:array[0..2]of array[0..2]of double= ( (-1,-2,-1),(0,0,0),(1,2,1) ); //グレースケール変換 procedure MamGrayScaleFilter(source,dest:TBitmap); //ガウシアンぼかしフィルタ procedure MamGausianFilter(source,dest:TBitmap); //ソーベル(境界[エッジ])フィルタ procedure MamSobelFilter(source,dest:TBitmap); implementation procedure MamGausianFilter(source,dest:TBitmap); var i,j,x,y,mn,xx,yy:NativeInt; drgb:TRRGB; saa,daa:TRGBArrArr; summ:extended; begin if not assigned(dest) then dest:=TBitmap.Create; dest.Width:=source.Width; dest.Height:=source.Height; dest.PixelFormat:=pf24bit; for j := 0 to source.Height-1 do begin saa[j]:=source.ScanLine[j]; daa[j]:=dest.ScanLine[j]; end; mn:=1; for j := 0 to source.Height-1 do begin for i := 0 to source.Width-1 do begin drgb.R:=0; drgb.G:=0; drgb.B:=0; summ:=0; for y := 0 to mn*2 do for x := 0 to mn*2 do begin xx:=i+x-mn; yy:=j+y-mn; if not ((xx<0) or (xx>=source.width) or (yy<0) or (yy>=source.height)) then begin summ:=summ+gauss3[x,y]; end; end; for y := 0 to mn*2 do for x := 0 to mn*2 do begin xx:=i+x-mn; yy:=j+y-mn; if not ((xx<0) or (xx>=source.width) or (yy<0) or (yy>=source.height)) then begin drgb.R:=drgb.R+gauss3[x,y]*saa[yy,xx].R/summ; drgb.G:=drgb.G+gauss3[x,y]*saa[yy,xx].G/summ; drgb.B:=drgb.B+gauss3[x,y]*saa[yy,xx].B/summ; end; end; if drgb.R<0 then drgb.R:=0 else if drgb.R>255 then drgb.R:=255; if drgb.G<0 then drgb.G:=0 else if drgb.G>255 then drgb.G:=255; if drgb.B<0 then drgb.B:=0 else if drgb.B>255 then drgb.B:=255; daa[j,i].R:=Round(drgb.R); daa[j,i].G:=Round(drgb.G); daa[j,i].B:=Round(drgb.B); end; end; end; procedure MamSobelFilter(source,dest:TBitmap); var gray:TBitmap; i,j,x,y,mn,xx,yy:NativeInt; drgbh,drgbv:TRRGB; gaa,saa,daa:TRGBArrArr; begin gray:=TBitmap.Create; //グレースケール画像を作成する MamGrayScaleFilter(source,gray); if not assigned(dest) then dest:=TBitmap.Create; dest.Width:=source.Width; dest.Height:=source.Height; dest.PixelFormat:=pf24bit; for j := 0 to gray.Height-1 do begin gaa[j]:=gray.ScanLine[j]; saa[j]:=source.ScanLine[j]; daa[j]:=dest.ScanLine[j]; end; mn:=1; for j := 0 to gray.Height-1 do begin for i := 0 to gray.Width-1 do begin drgbh.R:=0; drgbv.R:=0; for y := 0 to 2 do for x := 0 to 2 do begin xx:=i+x-mn; yy:=j+y-mn; if not ((xx<0) or (xx>=gray.width) or (yy<0) or (yy>=gray.height)) then begin drgbh.R:=drgbh.R+Sobelh[x,y]*gaa[yy,xx].R; drgbv.R:=drgbv.R+Sobelv[x,y]*gaa[yy,xx].R; end; end; drgbh.R:=Sqrt(drgbh.R*drgbh.R+drgbv.R*drgbv.R); if drgbh.R<0 then drgbh.R:=0 else if drgbh.R>255 then drgbh.R:=255; daa[j,i].R:=Round(drgbh.R); daa[j,i].G:=daa[j,i].R; daa[j,i].B:=daa[j,i].R; end; end; gray.Free; end; //グレースケール変換 procedure MamGrayScaleFilter(source,dest:TBitmap); var lines:PRGBArr; //source lined:PRGBArr; //dest v:byte; x,y:integer; begin if not assigned(dest) then dest:=TBitmap.Create; source.PixelFormat:=pf24bit; dest.PixelFormat:=pf24bit; dest.Width:=source.Width; dest.Height:=source.Height; for y := 0 to source.Height-1 do begin lines:=source.ScanLine[y]; lined:=dest.ScanLine[y]; for x := 0 to source.Width-1 do begin v:=round( 0.299*lines[x].R+ 0.587*lines[x].G+ 0.114*lines[x].B ); lined[x].R:=v; lined[x].G:=v; lined[x].B:=v; end; end; end; end.