なんとなく、ふわっと・・

写真と画像処理関係とひとりごとをなんとなく書き溜めていきたい

今日の夕暮れ

2007-10-20 21:39:31 | 写真






谷田部、つくば市


Comment

Delphi で Rinkaku Application その8

2007-10-20 00:49:08 | Delphi

前回に引き続き、Turbo Delphi で Rinkaku Application をつくる、の8回目。

今回は、前回までで取りきれないかも知れないノイズを、エッジを保つ平均化である
Kuwahara() フィルタでつくって処理することを試す。

Kuwahara() 自体の論理は、C# ですでにここで説明したので繰り返すことはしない。
今回は、これをグレースケールに変換したここと同等なものを Turbo Delphi で
つくる。ただし、C# のときは手抜きしていた統計処理を今回は厳密に標本分散
計算して、それが最小な区画から平均をとることにする。

さっそく実装しよう。RinkakuUtils.pas に以下の関数を追加する。

function Kuwahara8(var bmp: TBitmap; nBlock: integer;
                                bDetail: Boolean = true): Boolean;
var
  w, h, x, y, i, ix, iy, block, sblock, numBlock: integer;
  indx, min, d: integer;
  t: double;

  tmp: TBitmap;

  src, dst: TBmpData8;

  sum: array[0..3] of integer;
  sig: array[0..3] of integer;
  Xini: array[0..3] of integer;
  Yini: array[0..3] of integer;
begin
  result := false;
  if bmp.PixelFormat <> pf8bit then exit;

  if (nBlock > 8) or (nBlock < 1) then exit;

  w := bmp.Width;
  h := bmp.Height;

  block := nBlock * 2 + 1;
  sblock := block - 1;

  numBlock := block * block;

  tmp := TBitmap.Create;
  tmp.PixelFormat := pf24bit;
  tmp.Width := w + sblock * 2;
  tmp.Height := h + sblock * 2;
  tmp.Canvas.Draw(sblock, sblock, bmp);
  GrayScale(tmp);

  src := TBmpData8.Create(tmp);
  dst := TBmpData8.Create(bmp);

  for y := 0 to h-1 do
    for x := 0 to w-1 do
    begin

      Xini[0] := x - sblock; Yini[0] := y - sblock;     // upper-left
      Xini[1] := x; Yini[1] := y - sblock;              // upper-right
      Xini[2] := x; Yini[2] := y;                       // lower-right
      Xini[3] := x - sblock; Yini[3] := y;              // lower-left;

      for i := 0 to 3 do
      begin

        sum[i] := 0;
        for ix := Xini[i] to Xini[i] + sblock do
        for iy := Yini[i] to Yini[i] + sblock do
          sum[i] := sum[i] + src[ix+sblock, iy+sblock]^;

        sum[i] := sum[i] div numBlock;

        sig[i] := 0;
        for ix := Xini[i] to Xini[i] + sblock do
          for iy := Yini[i] to Yini[i] + sblock do
          begin
            d := src[ix+sblock, iy+sblock]^;
            sig[i] := sig[i] + (sum[i] - d) * (sum[i] - d);
          end;

        sig[i] := sig[i] div numBlock;
      end;

      min := 90000; indx := 0;

      for i := 0 to 3 do
        if (sig[i] < min) then
        begin
          min := sig[i];
          indx:= i;
        end;

      if (bDetail) then
      begin
        t := Max(0.5, 1.0 - Sqrt(sig[indx]) / 60);
        dst[x, y]^ := AdjustByte(t * sum[indx] + (1 - t) * dst[x, y]^);
      end
      else
        dst[x, y]^ := AdjustByte(sum[indx]);

    end;

  dst.Free;
  src.Free;

  tmp.Free;

  result := true;

end;


この実装の仕方は C# のときとは違う。カレントピクセルを含む小区画の
サイズは nBlock で設定するが、今回は nBlock*2 - 1 であり、nBlock = 1 は
C# のときの2、nBlock = 2 は C# のときの4に相当する。 通常は、nBlock = 1 で
十分である。

このテストコードを以下に示す。

uses
  VCLImageUtils, RinkakuUtils, Clipbrd;

procedure TForm1.Button1Click(Sender: TObject);
var
  bmp, tmp: TBitmap;
begin
  bmp := LoadPng('C:\Home\ImgWork\RaceQueen.png');
  if not Assigned(bmp) then exit;
  bmp.PixelFormat := pf24bit;

  tmp := BmpClone(bmp);

  if Rinkaku(tmp, 15) and Contrast8(tmp, 100, 0.04) and
     AntiBlackOut(bmp, tmp, 60, 30, 0.8)
     and Kuwahara8(tmp, 1, true)
  then
  begin
    Canvas.Draw(5, 35, tmp);
    Clipboard.Assign(tmp);
  end;

  bmp.Free;
  tmp.Free;
end;


結果は



となる。Kuwahara8() を適用しない



と比べると、エッジの周辺、顔のぶつぶつなどが効果的に軽減されていることが分かるだろう。
なお、上の二つは少し同じだけコントラストを強めている。

bDetail = false のときには



となる。最初の画像と比べると、平均化が大きく、ノイズがより低減されているが
歯茎や毛先などのディテールが失われていて、より絵画的になっている。


今回はここまで。
次回は Kuwahara8() を拡張して、より効果的なフィルタを作って試す。

Comment

羽成公園にて

2007-10-20 00:33:28 | 写真






羽成公園、観音台1、つくば市


Comment

いつも

2007-10-20 00:26:41 | 写真


山木、つくば市

背が低いのに、いつもうつむいているから、なかなか顔を見られない。
やっと会えたね。おひさしぶり。

Comment

HiScore

2007-10-20 00:10:16 | その他



とくに狙ったわけじゃないのに。
分布がたまたま開きやすかったんだろう。


Comment

Y

2007-10-20 00:04:23 | rinkaku




Comment