Beberapa hari yang lalu sempat main-main dan nyasar ke tema bilateral filtering. Salah satu aplikasinya adalah sebagai filter awal sebelum melakukan upsampling. Bilateral Filtering sendiri merupakan teknik penapisan citra yang melakukan proses penghalusan namun tetap menjaga struktur pada citra (tepi) dengan kata lain bilateral filtering merupakan salah satu teknik untuk melakukan edge-preserving smoothing pada citra. Hal yang membuat saya penasaran adalah hasil dari filtering yang didapat mirip dengan hasil dengan menggunakan teknik difusi non-linier.
Prinsip dari bilateral filtering bisa dibilang cukup sederhana karena pada dasarnya merupakan teknik yang berbasis pada ketetanggaan (spatial windowing) seperti pada perata-rataan tetangga(konvolusi diskret) atau penapisan median. Proses pada bilateral filtering dapat dibagi menjadi dua proses yaitu seleksi dan penapisan itu sendiri. Proses seleksi bertujuan mengikut-sertakan piksel-piksel tetangga yang masuk dalam kriteria. Fungsi kriteria yang digunakan adalah fungsi pembatas berdasarkan ‘jarak’ nilai piksel. Proses penapisannya sendiri dapat menggunakan penapisan linier (menggunakan kernel box atau gaussian) atau Penapisan non-linier (median filter).
Algoritma bilateral filtering memiliki dua parameter (selain parameter berupa citra yang difilter tentunya) yang perlu ditentukan secara manual yaitu jangkauan tetangga yang termasuk dalam proses seleksi dan jarak maksimum yang lolos seleksi. Dalam kode pascal saya mengimplementasi sebagai berikut :
//default value
fdr := 0.025; { range dalam skala 0.0 ... 1.0 }
dr := Round(255 * fdr);
dw := 7; { neighborhood window size }
Untuk kode secara keseluruhan bisa dilihat di bawah, namun ada hal yang perlu dicatat yaitu kode di bawah ini melakukan filtering pada kanal luminance dari citra berwarna yang digunakan sebagai nilai skala pada tiap kanal (R, G, dan B) dan bobot yang digunakan merupakan bobot seragam (box filter). Variasi dari kode ini dapat dilakukan hal lainnya seperti melakukan filtering pada tiap kanal, menggunakan kernel gaussian sebagai kernel konvolusi, ataupaun menggunakan median filtering sebagai pengganti konvolusi.
procedure TFrmMain.BilateralFilteringExecute(Sender: TObject);
var
i, j, k, l : integer;
dr, dw, mid, n : integer;
fdr, scale, tmpf : double;
b, b2 : TBitmap;
p : array of PArrRGB;
p2 : PArrRGB;
cur : TWarnaRGB;
sum, tmp : integer;
tmpstr : string;
function _ok(x,y:integer):boolean;begin
result := (X >= 0) and (y >= 0) and (x < b.Width) and (y < b.Height);
end;
begin
b := citra_make_greyscale(image1.picture.bitmap);
b2 := Image1.Picture.Bitmap;
setlength(p, b.Height);
for j := 0 to b.Height-1 do
p[j] := b.ScanLine[j];
fdr := 0.025;
dr := Round(255 * fdr);
dw := 7;
GetFloatParam('Range', 'bf.range', fdr);
GetIntParam('Window Size', 'bf.window_size', dw);
if dw and 1 <> 1 then inc(dw);//make sure it's odd
mid := dw div 2;
for j := 0 to b.Height-1 do begin
p2 := b2.ScanLine[j];
for i := 0 to b.Width-1 do begin
cur := p[j][i];
n := 0;
sum := 0;
for l := -mid to mid do begin
for k := -mid to mid do begin
if _ok(i+k, j+l) and (abs(cur.r-p[j+l][i+k].r)<=dr) then begin
inc(n);
sum := sum + p[j+l][i+k].r;
end;
end;
end;
//calc average
if n >= 0 then begin
tmp := round(sum / n);
if cur.r > 0 then
scale := tmp / cur.r
else
scale := tmp;
p2[i].r := clamp(round(scale * p2[i].r));
p2[i].g := clamp(round(scale * p2[i].g));
p2[i].b := clamp(round(scale * p2[i].b));
end;
end;
end;
b.Free;
image1.refresh;
end;
Filed under: delphi, image processing, programming | 2 Comments

kedua prosedur ini untuk apa ya..?
GetFloatParam(’Range’, ‘bf.range’, fdr);
GetIntParam(’Window Size’, ‘bf.window_size’, dw);
oh, itu untuk minta input parameter dari user (kalau dalam mode interaktif, di program saya) atau dari variabel (kalo mode script)