今回は画像の特定の部分を隠蔽するために使用するモザイクフィルタを取り上げます。アルゴリズムなんてレベルの話ではなく、指定されたブロックサイズに従ってピクセルを切り出して輝度別に平均を取り、ブロックを平均値で塗りつぶすだけの単純な作業です。
今回はブロックサイズを自由に設定できて、モザイクをかける範囲を直接指定できる実用的な関数を作りたいと思います。
WSizeとHSizeでモザイクのブロックサイズを指定し、Clipでモザイクをかけるクリッピングエリアを指定します。
procedure Mozaic(Bitmap: TBitmap; WSize, HSize: Integer; Clip: TRect);
var
X, Y, I, J: Integer;
xR, xG, xB, XX, YY: Integer;
Cnt, BlockW, BlockH: Integer;
pSrcCache: PCacheLines;
pSrcLine: PLine24;
begin
if ((WSize < 1) or (HSize < 1)) or ((WSize = 1) and (HSize = 1)) then Exit;
{ クリッピングエリアの最適化 }
with Clip do
begin
if (Left = Right) or (Top = Bottom) then Exit;
if Left > Right then
begin
I := Left;
Left := Right;
Right := I;
end;
if Top > Bottom then
begin
I := Top;
Top := Bottom;
Bottom := I;
end;
if Left < 0 then Left := 0;
if Top < 0 then Top := 0;
if Right >= Bitmap.Width then Right := Bitmap.Width;
if Bottom >= Bitmap.Height then Bottom := Bitmap.Height;
{ ブロック数を計算する }
BlockW := (Right - Left) div WSize;
BlockH := (Bottom - Top) div HSize;
end;
Bitmap.PixelFormat := pf24bit;
pSrcCache := GetCacheLines(Bitmap);//全ラインのキャッシュ
try
for Y := 0 to BlockH do
begin
YY := Y * HSize + Clip.Top;
for X := 0 to BlockW do
begin
XX := X * WSize + Clip.Left;
xR := 0;
xG := 0;
xB := 0;
Cnt := 0;
{ ピクセルを切り出して輝度を加算する }
for I := YY to YY+HSize -1 do
begin
if I >= Clip.Bottom then Continue;
pSrcLine := pSrcCache^[I];
for J := XX to XX+WSize -1 do
begin
if J >= Clip.Right then Continue;
with pSrcLine^[J] do
begin
Inc(xB, B);
Inc(xG, G);
Inc(xR, R);
end;
Inc(Cnt);
end;
end;
if Cnt = 0 then Continue;
{ 平均を計算 }
xR := Trunc(xR / Cnt + 0.5);
xG := Trunc(xG / Cnt + 0.5);
xB := Trunc(xB / Cnt + 0.5);
if xR > 255 then xR := 255 else if xR < 0 then xR := 0;
if xG > 255 then xG := 255 else if xG < 0 then xG := 0;
if xB > 255 then xB := 255 else if xB < 0 then xB := 0;
{ ブロックの塗り潰し }
for I := YY to YY+HSize -1 do
begin
if I >= Clip.Bottom then Continue;
pSrcLine := pSrcCache^[I];
for J := XX to XX+WSize -1 do
begin
if J >= Clip.Right then Continue;
with pSrcLine^[J] do
begin
B := xB;
G := xG;
R := xR;
end;
end;
end;
end;
end;
finally
FreeMem(pSrcCache);
end;
end;
|