Edge Detection dengan Delphi

Edge adalah batas antara dua daerah dengan nilai gray-level yang relatif berbeda atau dengan kata lain edge merupakan tempat-tempat yang memiliki perubahan intensitas yang besar dalam jarak yang pendek

Program yang di buat ini sebenarnya sudah komplit untuk mengolah sebuah citra. Tapi dalam pembahasan ini kita fokuskan pada olah citra dengan menggunakan edge detection.

untuk membuatnya, desain form seperti gambar di samping.



di bawah ini source code nya:

unit MainUnit;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtDlgs, Menus, StdCtrls, ExtCtrls, Spin;

type
TRGBTripleArray = array[0..10000] of TRGBTriple;
PRGBTripleArray = ^TRGBTripleArray;

T3x3FloatArray = array[0..2] of array[0..2] of Extended;

TForm1 = class(TForm)
Image1: TImage;
MainMenu1: TMainMenu;
File1: TMenuItem;
Open1: TMenuItem;
OpenPictureDialog1: TOpenPictureDialog;
GroupBox1: TGroupBox;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;
Edit6: TEdit;
Edit7: TEdit;
Edit8: TEdit;
Edit9: TEdit;
ComboBox1: TComboBox;
Button1: TButton;
SavePictureDialog1: TSavePictureDialog;
Save1: TMenuItem;
SaveAs1: TMenuItem;
N1: TMenuItem;
Exit1: TMenuItem;
Edit10: TEdit;
Label1: TLabel;
Edit11: TMenuItem;
Undo1: TMenuItem;
GroupBox2: TGroupBox;
SpinEdit1: TSpinEdit;
Button2: TButton;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
RadioButton3: TRadioButton;
RadioButton4: TRadioButton;
RadioButton5: TRadioButton;
Reset1: TMenuItem;
Help1: TMenuItem;
About1: TMenuItem;
procedure Open1Click(Sender: TObject);
procedure EditChange(Sender : TObject);
procedure SetMask(a1, a2, a3, a4, a5, a6, a7, a8, a9 : Extended ; ABias : integer);
procedure FormCreate(Sender: TObject);
procedure ComboBox1Select(Sender: TObject);
procedure Button1Click(Sender: TObject);
function Convolve(ABitmap : TBitmap ; AMask : T3x3FloatArray ; ABias : integer) : TBitmap;
procedure SaveAs1Click(Sender: TObject);
procedure Save1Click(Sender: TObject);
procedure Exit1Click(Sender: TObject);
procedure Undo1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
function Threshold(ABitmap : TBitmap ; AThreshold : byte ;
Intensity,
Saturation,
Red,
Green,
Blue : boolean) : TBitmap;
procedure Reset1Click(Sender: TObject);
procedure About1Click(Sender: TObject);
private
{ Private declarations }
Mask : T3x3FloatArray;
Bias : integer;
UndoBitmap : TBitmap;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses AboutUnit;

{$R *.dfm}

// initialization
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Tag := 0; Edit2.Tag := 1; Edit3.Tag := 2;
Edit4.Tag := 3; Edit5.Tag := 4; Edit6.Tag := 5;
Edit7.Tag := 6; Edit8.Tag := 7; Edit9.Tag := 8;
Edit10.Tag := 9; // bias

SetMask(1, 1, 1,
1, 1, 1,
1, 1, 1, 0);

UndoBitmap := TBitmap.Create;
UndoBitmap.PixelFormat := pf24bit;
end;

// preset masks
procedure TForm1.ComboBox1Select(Sender: TObject);
begin
if ComboBox1.ItemIndex = 0 then // uniform smoothing
SetMask(1, 1, 1,
1, 1, 1,
1, 1, 1, 0);

if ComboBox1.ItemIndex = 1 then // gaussian smoothing
SetMask(1/36, 1/9, 1/36,
1/9, 4/9, 1/9,
1/36, 1/9, 1/36, 0);

if ComboBox1.ItemIndex = 2 then // edge detection
SetMask(-1, -1, -1,
-1, 8, -1,
-1, -1, -1, 0);

if ComboBox1.ItemIndex = 3 then // vertical edge detection
SetMask( 0, 0, 0,
-1, 2, -1,
0, 0, 0, 0);

if ComboBox1.ItemIndex = 4 then // horizontal edge detection
SetMask( 0, -1, 0,
0, 2, 0,
0, -1, 0, 0);

if ComboBox1.ItemIndex = 5 then // enhanced detail
SetMask( 0, -1, 0,
-1, 9, -1,
0, -1, 0, 0);

if ComboBox1.ItemIndex = 6 then // enhanced focus
SetMask(-1, 0, -1,
0, 7, 0,
-1, 0, -1, 0);

if ComboBox1.ItemIndex = 7 then // emboss filter
SetMask(-1, -1, 0,
-1, 0, 1,
0, 1, 1, 128);

if ComboBox1.ItemIndex = 8 then // lighten
SetMask( 0, 0, 0,
0, 1, 0,
0, 0, 0, 20);

if ComboBox1.ItemIndex = 9 then // darken
SetMask( 0, 0, 0,
0, 1, 0,
0, 0, 0, -20);
end;

procedure TForm1.EditChange(Sender : TObject);
Var
LTag : byte;
LValue : Extended;
begin
LTag := TEdit(Sender).Tag;

if (TEdit(Sender).Text = '') or (TEdit(Sender).Text = '-')
then LValue := 0
else LValue := StrToFloat(TEdit(Sender).Text);

if LTag = 9 then begin
if (LValue > 255) or (Frac(LValue) <> 0) then begin
ShowMessage('the bias has to be a whole number between -255 and 255');
Exit;
end;
Bias := trunc(LValue);
Exit;
end;

Mask[LTag mod 3, LTag div 3] := LValue;
end;

procedure TForm1.SetMask(a1, a2, a3, a4, a5, a6, a7, a8, a9 : Extended ; ABias : integer);
begin
Edit1.Text := FloatToStr(a1);
Edit2.Text := FloatToStr(a2);
Edit3.Text := FloatToStr(a3);
Edit4.Text := FloatToStr(a4);
Edit5.Text := FloatToStr(a5);
Edit6.Text := FloatToStr(a6);
Edit7.Text := FloatToStr(a7);
Edit8.Text := FloatToStr(a8);
Edit9.Text := FloatToStr(a9);
Edit10.Text := IntToStr(ABias);
end;

// open a bitmap into the image
procedure TForm1.Open1Click(Sender: TObject);
begin
if not OpenPictureDialog1.Execute then Exit;
Image1.Picture.Bitmap.LoadFromFile(OpenPictureDialog1.FileName);
SaveAs1.Enabled := True;
Save1.Enabled := True;
Reset1.Enabled := True;
end;

// save as new bitmap file
procedure TForm1.SaveAs1Click(Sender: TObject);
begin
if not SavePictureDialog1.Execute then Exit;

Image1.Picture.Bitmap.SaveToFile(SavePictureDialog1.FileName);
end;

// overwrite original bitmap file
procedure TForm1.Save1Click(Sender: TObject);
begin
Image1.Picture.Bitmap.SaveToFile(OpenPictureDialog1.FileName);
end;

// convolve
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Save1.Enabled then Exit;

if (Image1.Picture.Bitmap.Width < 3) or (Image1.Picture.Bitmap.Height < 3) then begin
ShowMessage('the image is too small to perform convolution on');
Exit;
end;

UndoBitmap.Width := Image1.Picture.Bitmap.Width;
UndoBitmap.Height := Image1.Picture.Bitmap.Height;
UndoBitmap.Canvas.Draw(0, 0, Image1.Picture.Bitmap);
Undo1.Enabled := True;

Image1.Picture.Bitmap := Convolve(Image1.Picture.Bitmap, Mask, Bias);
end;

function TForm1.Convolve(ABitmap : TBitmap ; AMask : T3x3FloatArray ; ABias : integer) : TBitmap;
Var
LRow1, LRow2, LRow3, LRowOut : PRGBTripleArray;
LRow, LCol : integer;
LNewBlue, LNewGreen, LNewRed : Extended;
LCoef : Extended;
begin

LCoef := 0;
for LRow := 0 to 2 do for LCol := 0 to 2 do LCoef := LCoef + AMask[LCol, LRow];
if LCoef = 0 then LCoef := 1;

Result := TBitmap.Create;

Result.Width := ABitmap.Width - 2;
Result.Height := ABitmap.Height - 2;
Result.PixelFormat := pf24bit;

LRow2 := ABitmap.ScanLine[0];
LRow3 := ABitmap.ScanLine[1];

for LRow := 1 to ABitmap.Height - 2 do begin

LRow1 := LRow2;
LRow2 := LRow3;
LRow3 := ABitmap.ScanLine[LRow + 1];

LRowOut := Result.ScanLine[LRow - 1];

for LCol := 1 to ABitmap.Width - 2 do begin

LNewBlue :=
(LRow1[LCol-1].rgbtBlue*AMask[0,0]) + (LRow1[LCol].rgbtBlue*AMask[1,0]) + (LRow1[LCol+1].rgbtBlue*AMask[2,0]) +(LRow2[LCol-1].rgbtBlue*AMask[0,1]) + (LRow2[LCol].rgbtBlue*AMask[1,1]) + (LRow2[LCol+1].rgbtBlue*AMask[2,1]) +
(LRow3[LCol-1].rgbtBlue*AMask[0,2]) + (LRow3[LCol].rgbtBlue*AMask[1,2]) + (LRow3[LCol+1].rgbtBlue*AMask[2,2]);
LNewBlue := (LNewBlue / LCoef) + ABias;
if LNewBlue > 255 then LNewBlue := 255;
if LNewBlue < 0 then LNewBlue := 0;

LNewGreen :=
(LRow1[LCol-1].rgbtGreen*AMask[0,0])+(LRow1[LCol].rgbtGreen*AMask[1,0])+ (LRow1[LCol+1].rgbtGreen*AMask[2,0]) +(LRow2[LCol-1].rgbtGreen*AMask[0,1]) + (LRow2[LCol].rgbtGreen*AMask[1,1]) + (LRow2[LCol+1].rgbtGreen*AMask[2,1]) +
(LRow3[LCol-1].rgbtGreen*AMask[0,2]) + (LRow3[LCol].rgbtGreen*AMask[1,2]) + (LRow3[LCol+1].rgbtGreen*AMask[2,2]);
LNewGreen := (LNewGreen / LCoef) + ABias;
if LNewGreen > 255 then LNewGreen := 255;
if LNewGreen < 0 then LNewGreen := 0;

LNewRed :=
(LRow1[LCol-1].rgbtRed*AMask[0,0]) + (LRow1[LCol].rgbtRed*AMask[1,0]) + (LRow1[LCol+1].rgbtRed*AMask[2,0]) +(LRow2[LCol-1].rgbtRed*AMask[0,1]) + (LRow2[LCol].rgbtRed*AMask[1,1]) + (LRow2[LCol+1].rgbtRed*AMask[2,1]) +
(LRow3[LCol-1].rgbtRed*AMask[0,2]) + (LRow3[LCol].rgbtRed*AMask[1,2]) + (LRow3[LCol+1].rgbtRed*AMask[2,2]);
LNewRed := (LNewRed / LCoef) + ABias;
if LNewRed > 255 then LNewRed := 255;
if LNewRed < 0 then LNewRed := 0;

LRowOut[LCol-1].rgbtBlue := trunc(LNewBlue);
LRowOut[LCol-1].rgbtGreen := trunc(LNewGreen);
LRowOut[LCol-1].rgbtRed := trunc(LNewRed);

end;

end;

end;

// threshold
procedure TForm1.Button2Click(Sender: TObject);
Var
LThreshold : integer;
begin
if not Save1.Enabled then Exit;

UndoBitmap.Width := Image1.Picture.Bitmap.Width;
UndoBitmap.Height := Image1.Picture.Bitmap.Height;
UndoBitmap.Canvas.Draw(0, 0, Image1.Picture.Bitmap);
Undo1.Enabled := True;

LThreshold := SpinEdit1.Value;
if RadioButton2.Checked then LThreshold := trunc( LThreshold / 2 );

Image1.Picture.Bitmap := Threshold(Image1.Picture.Bitmap, LThreshold,
RadioButton1.Checked,
RadioButton2.Checked,
RadioButton3.Checked,
RadioButton4.Checked,
RadioButton5.Checked);
end;

function TForm1.Threshold(ABitmap : TBitmap ; AThreshold : byte ;
Intensity,
Saturation,
Red,
Green,
Blue : boolean) : TBitmap;
Var
LRowIn, LRowOut : PRGBTripleArray;
Ly, Lx : integer;
LBlack, LWhite : TRGBTriple;
LR, LG, LB : byte;
LR1, LR2 : integer;
begin

Result := TBitmap.Create;
Result.Width := ABitmap.Width;
Result.Height := ABitmap.Height;
Result.PixelFormat := pf24bit;

LBlack.rgbtBlue := 0; LBlack.rgbtGreen := 0; LBlack.rgbtRed := 0;
LWhite.rgbtBlue := 255; LWhite.rgbtGreen := 255; LWhite.rgbtRed := 255;

for Ly := 0 to ABitmap.Height - 1 do begin
LRowIn := ABitmap.ScanLine[Ly];
LRowOut := Result.ScanLine[Ly];
for Lx := 0 to ABitmap.Width - 1 do begin

LR := LRowIn[Lx].rgbtRed;
LG := LRowIn[Lx].rgbtGreen;
LB := LRowIn[Lx].rgbtBlue;

if Intensity then begin

if (0.3 * LR) + (0.59 * LG) + (0.11 * LB) >= AThreshold
then LRowOut[Lx] := LWhite
else LRowOut[Lx] := LBlack;

end else if Saturation then begin

LR1 := trunc( (-0.105465 * LR) + (-0.207424 * LG) + (0.312889 * LB) );
LR2 := trunc( (0.445942 * LR) + (-0.445942 * LG) );
if Sqrt( Sqr(LR1) + Sqr(LR2) ) >= AThreshold
then LRowOut[Lx] := LWhite
else LRowOut[Lx] := LBlack;

end else if Red then begin

if LR >= AThreshold then LRowOut[Lx] := LWhite
else LRowOut[Lx] := LBlack;

end else if Green then begin

if LG >= AThreshold then LRowOut[Lx] := LWhite
else LRowOut[Lx] := LBlack;

end else begin

if LB >= AThreshold then LRowOut[Lx] := LWhite
else LRowOut[Lx] := LBlack;

end;

end;
end;

end;

// restore previous bitmap
procedure TForm1.Undo1Click(Sender: TObject);
begin
Image1.Picture.Bitmap.Width := UndoBitmap.Width;
Image1.Picture.Bitmap.Height := UndoBitmap.Height;
Image1.Canvas.Draw(0, 0, UndoBitmap);
Undo1.Enabled := False;
end;

// restore original bitmap
procedure TForm1.Reset1Click(Sender: TObject);
begin
Image1.Picture.Bitmap.LoadFromFile(OpenPictureDialog1.FileName);
end;

procedure TForm1.Exit1Click(Sender: TObject);
begin
Close;
end;

procedure TForm1.About1Click(Sender: TObject);
begin
AboutBox.ShowModal;
end;

end.

Untuk menjalankannya, load gambar melalui file->open dan pilih gambar yang di inginkan. Setelah itu pada combobox pilih item edge detection lalu klik button convolve.




















Hasil yang didapat adalah perubahan warna citra putih pada daerah yang memiliki perbedaan intensitas warna yang besar pada jarak yang pendek.






Komentar

Postingan Populer