Awalnya saya ingin menunda untuk menulis ini karena belum mendapatkan informasi yang cukup untuk diacu karena kebanyakan masih pemahaman pribadi yang subjektif. Tetapi akhirnya saya tulis juga dengan alasan sekedar menceritakan hal-hal yang saya capai baru-baru ini (supaya tidak lupa).
Utak-atik kali ini didasarkan pada rasa penasaran Saya ketika membaca Buku Digital Image Processing khsususnya pada bagian model regularisasi atau variasional. Disebabkan dasar matematika (khususnya kalkulus multivariabel dan aljabar linier lanjutan) saya yang agak lemah. Saya jadi lambat mencerna isi dari buku tersebut. Selama ini operasi-operasi pengolahan citra yang saya buat implementasinya hanya dalam domain spasial. Untuk operasi dalam domain frekuensi sengaja saya tunda karena saya sendiri belum paham untuk mengimplementasi algoritma Transformasi Fourier (FFT) sendiri. Kode untuk melakukan FFT sebenarnya sudah banyak tersedia. Persoalannya adalah karena tujuan saya untuk belajar maka sebisa mungkin saya paham dulu teori dan prinsip algoritmanya baru nanti mungkin saya mulai ngoprek pengolahan citra dalam domain ini (domain wavelet kapan yah?).
Kembali lagi ke masalah difusi non-linier (non-linear diffusion) akhirnya saya kembali merujuk ke wikipedia dan om google untuk mempelajari lagi tentang difusi dan teori-teori yang terkait di berbagai bidang ilmu(matematika, fisika, dan biologi). Akhirnya setelah memaksa otak untuk mencerna prinsip dari proses difusi, saya mendapatkan ide untuk membuat implementasinya secara sederhana. Prinsipnya sederhana, berdasarkan teori difusi yang saya pahami seperti berikut
partikel-partikel dalam area berkonsentrasi tinggi akan bergerak menuju area dengan konsentrasi yang lebih rendah
Berdasarkan prinsip di atas saya memodelkan setiap pixel sebagai sebuah area. Intensitas pixel tersebut merupakan akibat dari akumulasi (banyaknya) partikel yang terakumulasi pada area tersebut. Asumsi saya proses difusi merupakan proses yang mempertahankan volum. Maka saya bisa membuat algoritma difusi dengan menggerakkan partikel dalam suatu area ke area lain yang terhubung (bertetangga). Sederhananya, ini hanya masalah mengurangi intensitas di suatu pixel sebesar delta dan menambahkan pixel lain di tetangganya sebesar delta juga. Konsentrasi diibaratkan intensitas.
Proses pemindahan intensitas tiap pixel tersebut dilakukan secara iteratif. Lama-kelamaan gambar pada citra akan nampak kabur. Sampai saat ini yang dilakukan baru difusi yang menurut saya linier dalam artian setiap pixel akan diproses tanpa mempertimbangkan pentingnya suatu pixel dalam mengandung informasi.
Implementasi Algoritma Difusi Linier dalam delphi
Potongan kode berikut mencoba untuk melakukan difusi linier untuk citra greyscale.
procedure TFrmMain.Diffuse1Execute(Sender: TObject);
{ Kamus }
const dir : array[0..7] of TPoint = (
(X:0;Y:-1),//UP
(X:1;Y:-1),
(X:1;Y:0),//RIGHT
(X:1;Y:1),
(X:0;Y:1),//DOWN
(X:-1;Y:1),
(X:-1;Y:0),//LEFT
(X:-1;Y:-1)
);
var
b : TBitmap;
p : array of PArrRGB;
cl : array of integer;
icl : array of integer;
j, i, k, l : integer;
minidx, mindir, amount : integer;
iter : integer;
function is_ok(x, y : integer): boolean;
begin result := (x>=0) and (x<b.Width) and (y>=0) and (y<b.Height); end;
{ Algoritma }
begin
b := citra_clone(Image1.Picture.Bitmap);
setlength(p, b.Height);
for j := 0 to b.Height-1 do p[j] := b.ScanLine[j];
for iter := 0 to 10 do begin
for j := 0 to b.Height-1 do begin
for i := 0 to b.Width-1 do begin
{ lihat pixel di sekitar p_current }
setlength(cl, 0);
setlength(icl, 0);
for l := 0 to high(dir) do begin
if is_ok(i+dir[l].X, j+dir[l].Y) then begin
setlength(cl, length(cl)+1);
cl[high(cl)] := p[j+dir[l].Y][i+dir[l].X].r;
setlength(icl, length(icl)+1);
icl[high(icl)] := l;
end;
end;
{ cari pixel tetangga p_dest dengan konsentrasi terrendah }
minidx := 0;
mindir := icl[0];
if length(cl)>0 then begin
for l := 1 to high(icl) do
if cl[l] > cl[minidx] then begin
minidx := l;
mindir := icl[l];
end;
{ pindahkan warna dari current pixel ke p_dest }
: linear diffusion
sedemikian sehingga nilai current pixel sama dengan nilai p_dest
k := (cl[minidx] + p[j][i].r) shr 1;
p[j][i] := warna_create(k, k, k);
p[j+dir[mindir].Y][i+dir[mindir].X] := p[j][i];
end;
end;
end;
end;
FrmImg.Preview(b, true);
Image1.Picture.Bitmap.Assign(b);
Image1.Refresh;
b.Free;
end;
Difusi Non-linier
Difusi yang bersifat non-linier dicapai dengan menggunakan faktor penskalaan pada jumlah intensitas pixel yang dipindahkan. faktor penskalaan ini bisa didapat menggunakan nilai fitur tepi (edge). Untuk setiap iterasi, citra yang mengandung fitur tepi dihitung ulang. Pixel yang merupakan bagian dari tepi maka intensitas tepinya besar sehingga koefisien skala pemindahannya menjadi kecil.
Implementasi Algoritma Difusi Non-linier dalam delphi
procedure TFrmMain.Diffuse1Execute(Sender: TObject);
{ Kamus }
const dir : array[0..7] of TPoint = (
(X:0;Y:-1),//UP
(X:1;Y:-1),
(X:1;Y:0),//RIGHT
(X:1;Y:1),
(X:0;Y:1),//DOWN
(X:-1;Y:1),
(X:-1;Y:0),//LEFT
(X:-1;Y:-1)
);
var
b : TBitmap;
bgrey : TBitmap;
bref : TBitmap;
p, pref , pgrey : array of PArrRGB;
cl : array of integer;
icl : array of integer;
j, i, k, l : integer;
minidx, mindir, amount : integer;
rmov, gmov, bmov : integer;
diffuse_coeff : real;
iter : integer;
function is_ok(x, y : integer): boolean;
begin result := (x>=0) and (x<b.Width) and (y>=0) and (y<b.Height); end;
{ Algoritma }
begin
b := citra_clone(Image1.Picture.Bitmap);
setlength(p, b.Height);
for j := 0 to b.Height-1 do p[j] := b.ScanLine[j];
for iter := 0 to 10 do begin
bgrey := citra_make_greyscale(b);
bref := citra_filter_mean(bgrey, KLAPLACIANOFGAUSSIAN);
setlength(pref, bref.Height);
for j := 0 to bref.Height-1 do pref[j] := bref.ScanLine[j];
setlength(pgrey, bgrey.Height);
for j := 0 to bgrey.Height-1 do pgrey[j] := bgrey.ScanLine[j];
for j := 0 to b.Height-1 do begin
for i := 0 to b.Width-1 do begin
{ lihat pixel di sekitar p_current }
setlength(cl, 0);
setlength(icl, 0);
for l := 0 to high(dir) do begin
if is_ok(i+dir[l].X, j+dir[l].Y) then begin
setlength(cl, length(cl)+1);
cl[high(cl)] := pgrey[j+dir[l].Y][i+dir[l].X].r;
setlength(icl, length(icl)+1);
icl[high(icl)] := l;
end;
end;
{ cari pixel tetangga p_dest dengan konsentrasi terrendah }
minidx := 0;
mindir := icl[0];
if length(cl)>0 then begin
for l := 1 to high(icl) do
if cl[l] > cl[minidx] then begin
minidx := l;
mindir := icl[l];
end;
{ pindahkan warna dari current pixel ke p_dest }
{ : non-linear diffusion }
{ sebesar amount = diffuse_coeff * current_pixel }
{ diffuse_coeff := 1 - edge_profile current pixel }
if pref[j][i].r < 80 then begin
diffuse_coeff := (255 - pref[j][i].r) / 255;
rmov := clamp(round(diffuse_coeff * ((p[j][i].r-p[j+dir[mindir].Y][i+dir[mindir].X].r) shr 1)));
gmov := clamp(round(diffuse_coeff * ((p[j][i].g-p[j+dir[mindir].Y][i+dir[mindir].X].g) shr 1)));
bmov := clamp(round(diffuse_coeff * ((p[j][i].b-p[j+dir[mindir].Y][i+dir[mindir].X].b) shr 1)));
with p[j][i] do begin
r := r - rmov;
g := g - gmov;
b := b - bmov;
end;
with p[j+dir[mindir].Y][i+dir[mindir].X] do begin
r := r + rmov;
g := g + gmov;
b := b + bmov;
end;
end;
end;
end;
end;
bref.free;
bgrey.Free;
end;
FrmImg.Preview(b, true);
Image1.Picture.Bitmap.Assign(b);
Image1.Refresh;
b.Free;
end;
Hasil Pengujian
Gbr 1. Foto sebelum smoothing
Gbr 2. Foto sesudah smoothing
Gbr 1. Foto sebelum smoothing
Gbr 2. Foto sesudah smoothing
Filed under: delphi, hacking, image processing, programming |
Tags: delphi, non-linear diffusion, source-code
wah…ternyata banyak ya metode penghalusan citra…
mana ya yang lebih baik sama metode median…
eh..mas peb..itu fotonya mas peb ya..
hmmm sama sapa ya..he2..
waa.. bisa minta programnya yg difusi non linier ini secara utuh nggak? kalo boleh minta kirim ke emailku ya.. thx.. soalnya ini ada tgs kul disuru cari macam2 algoritma untuk makul PCD, thanks2 so much ya..
@intan: kan sudah dikasi source-codenya di tulisan di atas?
mas, tolong tanya fungsi-fungsi ini source code nya bagaimana? dan nilai kembalinya apa?
citra_filter_mean(bgrey, KLAPLACIANOFGAUSSIAN);
high(dir)
clamp(int x)
klo bs sekalian jelaskan maksudnya, terima kasih byk
citra_filter_mean : konvolusi 2D, maksud fungsi itu (dalam konteks kode di atas) adalah menghasilkan citra yang berisi kekuatan edge (fitur citra yang harus dipertahankan).
high(dir) : menghasilkan indeks maksimum dari array dir
clamp(x) : int -> int
| x max = max
| true = x
maksudnya : menjamin nilai kembalian fungsi agar ada dalam jangkauan min <= x <= max