Implementasi Bilateral Filtering di Delphi

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;

13 comments

  1. Andri · Agustus 26, 2008

    kedua prosedur ini untuk apa ya..?

    GetFloatParam(‘Range’, ‘bf.range’, fdr);
    GetIntParam(‘Window Size’, ‘bf.window_size’, dw);

  2. pebbie · Agustus 26, 2008

    oh, itu untuk minta input parameter dari user (kalau dalam mode interaktif, di program saya) atau dari variabel (kalo mode script)

  3. Ping-balik: Mean Shift Filtering « GAIBlog
  4. ahmed · Juni 28, 2011

    Please I need this function in your code :citra_make_greyscale()
    or
    can you send the complete code to me by email:
    My email is : ah_h72@yahoo.com
    Please I need it.

  5. ahmed · Juni 28, 2011

    Also I can’t understand the GetFloatParam, GetIntParam and clamp functions. I think the project is not complete. Please send me the complete project.

    • pebbie · Juni 29, 2011

      sorry to disappoint you ahmed for i cannot give you the rest of the code. but if you are looking for greyscale transform you can find it in wikipedia how to do it. the GetXXXParam is a Dialog triggering function but only for a specific variable. a clamp function will only return values that are defined in it’s parameters (mostly 0-255 inclusive by default for a byte used as a pixel in the image). anyway, thank you for your visit.

  6. edi · Agustus 7, 2013

    kalo ini error dimana pak trim’s (hasil running dr coding di atas)
    [Error] Main.pas(471): Undeclared identifier: ‘GetFloatParam’
    [Error] Main.pas(472): Undeclared identifier: ‘GetIntParam’
    [Error] Main.pas(499): Undeclared identifier: ‘clamp’

  7. pebbie · Agustus 7, 2013
    procedure GetFloatParam(caption, varname: string;
      var target: double);
    var
      tmpstr: string;
      tmpf: double;
    begin
        tmpstr := inputbox('Parameter', caption, floattostr(target));
        if trystrtofloat(tmpstr, tmpf) then target := tmpf;
    end;
    
    procedure GetIntParam(caption, varname: string;
      var target: integer);
    var
      tmpstr: string;
      tmp: integer;
    begin
        tmpstr := inputbox('Parameter', caption, inttostr(target));
        if trystrtoint(tmpstr, tmp) then target := tmp;
    end;
    
    function clamp(n: integer; limit: integer = 255): integer;
    begin
      if n > limit then
        result := limit
      else
        if n < 0 then
          result := 0
        else
          result := n;
    end;
    
    • edi · Agustus 9, 2013

      Terimakasih banyak…akan saya coba…pak…

    • edi · Agustus 9, 2013

      Maaf udh saya coba, tapi ada error di bagian ini tolong di bantu lagi pak..
      [Error] Main.pas(471): Undeclared identifier: ‘TWarnaRGB’
      [Error] Main.pas(469): Undeclared identifier: ‘PArrRGB’
      [Error] Main.pas(480): Undeclared identifier: ‘citra_make_greyscale’
      [Error] Main.pas(506): ‘)’ expected but identifier ‘r’ found..

      Terima kasih…

      • edi · Agustus 9, 2013

        Sdh ktemu Pak problemnya, cuma ada satu lagi yg error;
        [Error] Main.pas(491): Undeclared identifier: ‘citra_make_greyscale’

        trimskasih

  8. edi · Agustus 9, 2013

    Sdh ktemu Pak problemnya, cuma ada satu lagi yg error;
    [Error] Main.pas(491): Undeclared identifier: ‘citra_make_greyscale’

    trimskasih

  9. http://Www.Computerdesksgiant.com · November 28, 2013

    hello!,I love your writinbg very so much!

    percentage we keep in touch more approximately your article
    on AOL? I require a specialist in this space to unravel my problem.
    Maybe that is you! Taking a loook ahead to see you.

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s