画像にアンシャープ,ガウシアン,ぼかし,ゴマ塩ノイズ除去(FMX) ~Delphiソースコード集
(参考)バイキュービック法(bicubic)で拡大縮小する(VCL)
(参考)バイキュービック法(bicubic)で拡大縮小する(FMX)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(VCL)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(FMX)
(参考)ソーベルフィルタ(Sobel filter)で境界(エッジ)検出(VCL)
画像フィルターを使用する為のファイルの準備
本ページの下部のソースコードをコピーして「UFMXMamBasicFilter.pas」ファイルを作成し、 プロジェクトフォルダ内に入れる。ソースコードの記述
プロジェクトを新規作成(FMXアプリケーション)し、フォーム(Form1)にTImageを2個、TButtonを5個配置する。Image1のPictureプロパティから、フィルタを適用したい画像をロードしておく。
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FMX.Controls.Presentation, FMX.StdCtrls, FMX.Objects;
type
TForm1 = class(TForm)
Image1: TImage;
Image2: TImage;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
private
{ private 宣言 }
public
{ public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
uses UFMXMamBasicFilter;
procedure TForm1.Button1Click(Sender: TObject);
begin
//Image1をグレースケールにしてImage2に表示
MamGrayScale(Image1.Bitmap,Image2.Bitmap);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
//Image1にアンシャープマスク(鮮鋭化)を適用してImage2に表示
MamUnSharp(Image1.Bitmap,Image2.Bitmap,3);
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
//Image1にガウシアンぼかし(ノイズ除去ぼかし)を適用してImage2に表示
MamGaussian(Image1.Bitmap,Image2.Bitmap,TMamGaussian.Gaussian5x5);
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
//Image1にぼかし(平滑化、平均化)を適用してImage2に表示
MamBlur(Image1.Bitmap,Image2.Bitmap,2);
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
//Image1にメディアンフィルタ(スパイク[ゴマ塩]ノイズの除去に有効)を
MamMedian(Image1.Bitmap,Image2.Bitmap,1);
end;
end.
実行する
実行ボタンを押して実行します。(デバッグ実行でもOK)Button1をクリックすると、Image1写真画像をグレースケール画像に変換してImage2に表示します。
Button2をクリックすると、Image1写真画像にアンシャープマスク(鮮鋭化)を適用してImage2に表示します。
Button3をクリックすると、Image1写真画像にガウシアンぼかし(ノイズ除去ぼかし)を適用してImage2に表示します。
Button4をクリックすると、Image1写真画像にぼかし(平滑化、平均化)を適用してImage2に表示します。
Button5をクリックすると、Image1写真画像にメディアンフィルタ(スパイク[ゴマ塩]ノイズの除去に有効)を適用してImage2に表示します。
「UFMXMamBasicFilter.pas」ファイルのソースコード
unit UFMXMamBasicFilter;
interface
uses System.Types,System.UITypes, System.Math,
System.Generics.Collections, System.Generics.Defaults,
FMX.Graphics, FMX.Types;
Type
TMamGaussian=(Gaussian3x3, Gaussian5x5, Gaussian7x7);
TMedian=record
v:Byte;
x:Integer;
y:Integer;
end;
//src画像のグレースケール画像をdestに作成する
procedure MamGrayScale(src,dest:FMX.Graphics.TBitmap);
//src画像にアンシャープマスク(鮮鋭化)を適用しdestに作成
//(Strength:0.1~10.0)
procedure MamUnSharp(src,dest:FMX.Graphics.TBitmap;Strength:Single=1);
//src画像にガウシアンぼかし(ノイズ除去ぼかし)を適用してdestに作成
procedure MamGaussian(src,dest:FMX.Graphics.TBitmap;
sm:TMamGaussian=TMamGaussian.Gaussian5x5);
//src画像にぼかし(平滑化、平均化)を適用してdestに作成
//(Strength:1~20)
procedure MamBlur(src,dest:FMX.Graphics.TBitmap;Strength:Integer=2);
//メディアンフィルタ(スパイク[ゴマ塩]ノイズの除去に有効)
//(Strength:1~4)
procedure MamMedian(src,dest:FMX.Graphics.TBitmap;Strength:Integer=1);
implementation
Type
TSRGBA=record B,G,R,A:Single; end;
TRGBA=record B,G,R,A:Byte; end;
TRGBAArr=array[0..64535 div 2] of TRGBA;
PRGBAArr=^TRGBAArr;
TRGBAArrArr=array[0..64535 div 2] of PRGBAArr;
TMn=array of array of single;
TGauss=array of array of single;
const
//ガウシアンフィルタ係数配列
gauss3:array[0..2]of array[0..2]of single=
(
(1,2,1),(2,4,2),(1,2,1)
);
gauss5:array[0..4]of array[0..4]of single=
(
( 1, 4, 6, 4, 1), ( 4,16,24,16, 4), ( 6,24,36,24, 6),
( 4,16,24,16, 4), ( 1, 4, 6, 4, 1)
);
gauss7:array[0..6]of array[0..6] of single=
(
( 1, 6, 15, 20, 15, 6, 1), ( 6, 36, 90,120, 90, 36, 6),
(15, 90,225,300,225, 90,15), (20,120,300,400,300,120,20),
(15, 90,225,300,225, 90,15), ( 6, 36, 90,120, 90, 36, 6),
( 1, 6, 15, 20, 15, 6, 1)
);
//Delphi標準のTArray.Sort(クイックソート)よりも速い
//コムソートを使用する
procedure CombSort(var a:Array Of TMedian);
//二つの整数の値を入れ替える
procedure SwapInt(var v1,v2:TMedian);
var sw:TMedian;
begin
sw:=v1;
v1:=v2;
v2:=sw;
end;
var between:Integer;//間隔
i,l,h:integer;
begin
l:=Low(a);
h:=High(a);
//初期の比較間隔
between:=System.Math.Floor((h-l+1)/1.3);
while between>0 do //比較間隔が0になったら終了
begin
i:=l;
while h>=(i+between) do
begin
if a[i].v>a[i+between].v then
SwapInt(a[i],a[i+between]);
inc(i);
end;
//比較間隔を小さくする(1.3で割って切り捨て)
between:=System.Math.Floor(between/1.3);
end;
end;
//src画像のグレースケール画像をdestに作成する
procedure MamGrayScale(src,dest:FMX.Graphics.TBitmap);
var v:byte;
x,y:integer;
SrcBmp,DestBmp:TBitmap;//src,destの一時画像
fRect:TRect;
SrcData,DestData:TBitmapData;
SrcRGBA,DestRGBA:PRGBAArr;
begin
if not assigned(src) then exit;
if not assigned(dest) then dest:=FMX.Graphics.TBitmap.Create;
dest.SetSize(src.Width,src.Height);
fRect.Left:=0;
fRect.Top:=0;
fRect.Width:=src.Width;
fRect.Height:=src.Height;
//PixelFormatはTPixelFormat.BGRAがデフォルト
SrcBmp:=FMX.Graphics.TBitmap.Create;
DestBmp:=FMX.Graphics.TBitmap.Create;
try
SrcBmp.SetSize(fRect.Width,fRect.Height);
SrcBmp.Canvas.BeginScene();
SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,true);
SrcBmp.Canvas.EndScene;
DestBmp.SetSize(fRect.Width,fRect.Height);
SrcBmp.Map(TMapAccess.Read,SrcData);
DestBmp.Map(TMapAccess.Write,DestData);
try
for y := 0 to SrcBmp.Height-1 do
begin
SrcRGBA:=SrcData.GetScanline(y);
DestRGBA:=DestData.GetScanline(y);
for x := 0 to fRect.Width-1 do
begin
v:=Round(
0.299*SrcRGBA[x].R+ 0.587*SrcRGBA[x].G+ 0.114*SrcRGBA[x].B
);
DestRGBA[x].R:=v;
DestRGBA[x].G:=v;
DestRGBA[x].B:=v;
DestRGBA[x].A:=255;
end;
end;
finally
SrcBmp.Unmap(SrcData);
DestBmp.Unmap(DestData);
end;
dest.Canvas.BeginScene();
dest.Canvas.DrawBitmap(DestBmp,fRect,fRect,1,true);
dest.Canvas.EndScene;
finally
SrcBmp.Free;
DestBmp.Free;
end;
end;
//src画像にアンシャープマスク(鮮鋭化)を適用しdestに作成
//(Strength:0.1~10.0)
procedure MamUnSharp(src,dest:FMX.Graphics.TBitmap;Strength:Single=1);
var m:array of array of Single;
mn,center:Integer;
x,y,i,j,xx,yy:Integer;
fRect:TRect;
SrcBmp,DestBmp:FMX.Graphics.TBitmap;//src,destの一時画像
SrcData,DestData:TBitmapData;
SrcRGBA,DestRGBA:TRGBAArrArr;
fSRGBA:TSRGBA;
begin
if not assigned(src) then exit;
if not assigned(dest) then dest:=FMX.Graphics.TBitmap.Create;
dest.SetSize(src.Width,src.Height);
if Strength<0.1 then Strength:=0.1;
if Strength>10 then Strength:=10;
fRect.Left:=0;
fRect.Top:=0;
fRect.Width:=src.Width;
fRect.Height:=src.Height;
mn:=3;
center:=(mn-1) div 2;
//アンシャープマスク カーネルの作成
SetLength(m,mn);
for y := Low(m) to High(m) do
begin
SetLength(m[y],mn);
for x := Low(m[y]) to High(m[y]) do
begin
if (y=center)and(x=center) then
m[y][x]:=1+8*Strength/9
else
m[y][x]:=-Strength/9;
end;
end;
//PixelFormatはTPixelFormat.BGRAがデフォルト
SrcBmp :=FMX.Graphics.TBitmap.Create;
DestBmp:=FMX.Graphics.TBitmap.Create;
try
SrcBmp.SetSize(fRect.Width,fRect.Height);
SrcBmp.Canvas.BeginScene();
SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,true);
SrcBmp.Canvas.EndScene;
DestBmp.SetSize(fRect.Width,fRect.Height);
//ビットマップのデータマップを取得
SrcBmp.Map(TMapAccess.Read,SrcData);
DestBmp.Map(TMapAccess.Write,DestData);
try
//スキャンラインの一括取得
for j := 0 to fRect.Height-1 do
begin
SrcRGBA[j]:=SrcData.GetScanLine(j);
DestRGBA[j]:=DestData.GetScanLine(j);
end;
for j := 0 to fRect.Height-1 do
begin
for i := 0 to fRect.Width-1 do
begin
fSRGBA.R:=0;
fSRGBA.G:=0;
fSRGBA.B:=0;
fSRGBA.A:=255;
for y := 0 to mn-1 do
begin
for x := 0 to mn-1 do
begin
yy:=j+(y-center);
if (yy<0)or(yy>=fRect.Height) then
yy:=j-(y-center);
xx:=i+(x-center);
if (xx<0)or(xx>=fRect.Width) then
xx:=i-(x-center);
fSRGBA.R:=fSRGBA.R+m[y][x]*SrcRGBA[yy][xx].R;
fSRGBA.G:=fSRGBA.G+m[y][x]*SrcRGBA[yy][xx].G;
fSRGBA.B:=fSRGBA.B+m[y][x]*SrcRGBA[yy][xx].B;
end;
end;
if fSRGBA.R>255 then fSRGBA.R:=255;
if fSRGBA.G>255 then fSRGBA.G:=255;
if fSRGBA.B>255 then fSRGBA.B:=255;
if fSRGBA.R<0 then fSRGBA.R:=0;
if fSRGBA.G<0 then fSRGBA.G:=0;
if fSRGBA.B<0 then fSRGBA.B:=0;
DestRGBA[j][i].R:=Round(fSRGBA.R);
DestRGBA[j][i].G:=Round(fSRGBA.G);
DestRGBA[j][i].B:=Round(fSRGBA.B);
DestRGBA[j][i].A:=Round(fSRGBA.A);
end;
end;
finally
SrcBmp.Unmap(SrcData);
DestBmp.Unmap(DestData);
end;
dest.Canvas.BeginScene();
dest.Canvas.DrawBitmap(DestBmp,fRect,fRect,1,true);
dest.Canvas.EndScene;
finally
SrcBmp.Free;
DestBmp.Free;
end;
end;
//src画像にガウシアンぼかし(ノイズ除去ぼかし)を適用してdestに作成
procedure MamGaussian(src,dest:FMX.Graphics.TBitmap;
sm:TMamGaussian=TMamGaussian.Gaussian5x5);
var m:array of array of Single;
mn,center:Integer;
msum:Single;
x,y,i,j,xx,yy:Integer;
fRect:TRect;
SrcBmp,DestBmp:FMX.Graphics.TBitmap;//src,destの一時画像
SrcData,DestData:TBitmapData;
SrcRGBA,DestRGBA:TRGBAArrArr;
fSRGBA:TSRGBA;
begin
if not assigned(src) then exit;
if not assigned(dest) then dest:=FMX.Graphics.TBitmap.Create;
dest.SetSize(src.Width,src.Height);
//行列の作成
mn:=3;
msum:=0;
if sm=TMamGaussian.Gaussian5x5 then mn:=5;
if sm=TMamGaussian.Gaussian7x7 then mn:=7;
SetLength(m,mn);
for j := Low(m) to High(m) do
begin
SetLength(m[j],mn);
for i := Low(m[j]) to High(m[j]) do
begin
if mn=3 then
begin
m[j][i]:=gauss3[j][i];
msum:=msum+gauss3[j][i];
end
else if mn=5 then
begin
m[j][i]:=gauss5[j][i];
msum:=msum+gauss5[j][i];
end
else
begin
m[j][i]:=gauss7[j][i];
msum:=msum+gauss7[j][i];
end;
end;
end;
center:=(mn-1) div 2;
fRect.Left:=0;
fRect.Top:=0;
fRect.Width:=src.Width;
fRect.Height:=src.Height;
//PixelFormatはTPixelFormat.BGRAがデフォルト
SrcBmp :=FMX.Graphics.TBitmap.Create;
DestBmp:=FMX.Graphics.TBitmap.Create;
try
SrcBmp.SetSize(fRect.Width,fRect.Height);
SrcBmp.Canvas.BeginScene();
SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,true);
SrcBmp.Canvas.EndScene;
DestBmp.SetSize(fRect.Width,fRect.Height);
//ビットマップのデータマップを取得
SrcBmp.Map(TMapAccess.Read,SrcData);
DestBmp.Map(TMapAccess.Write,DestData);
try
//スキャンラインの一括取得
for j := 0 to fRect.Height-1 do
begin
SrcRGBA[j]:=SrcData.GetScanLine(j);
DestRGBA[j]:=DestData.GetScanLine(j);
end;
for j := 0 to fRect.Height-1 do
begin
for i := 0 to fRect.Width-1 do
begin
fSRGBA.R:=0;
fSRGBA.G:=0;
fSRGBA.B:=0;
fSRGBA.A:=255;
//UnSharp行列の作成
for y := 0 to mn-1 do
begin
for x := 0 to mn-1 do
begin
yy:=j+(y-center);
if (yy<0)or(yy>=fRect.Height) then
yy:=j-(y-center);
xx:=i+(x-center);
if (xx<0)or(xx>=fRect.Width) then
xx:=i-(x-center);
fSRGBA.R:=fSRGBA.R+m[y,x]*SrcRGBA[yy][xx].R/msum;
fSRGBA.G:=fSRGBA.G+m[y,x]*SrcRGBA[yy][xx].G/msum;
fSRGBA.B:=fSRGBA.B+m[y,x]*SrcRGBA[yy][xx].B/msum;
end;
end;
if fSRGBA.R>255 then fSRGBA.R:=255;
if fSRGBA.G>255 then fSRGBA.G:=255;
if fSRGBA.B>255 then fSRGBA.B:=255;
if fsRGBA.R<0 then fSRGBA.R:=0;
if fSRGBA.G<0 then fSRGBA.G:=0;
if fSRGBA.B<0 then fSRGBA.B:=0;
DestRGBA[j][i].R:=Round(fSRGBA.R);
DestRGBA[j][i].G:=Round(fSRGBA.G);
DestRGBA[j][i].B:=Round(fSRGBA.B);
DestRGBA[j][i].A:=Round(fSRGBA.A);
end;
end;
finally
SrcBmp.Unmap(SrcData);
DestBmp.Unmap(DestData);
end;
dest.Canvas.BeginScene();
dest.Canvas.DrawBitmap(DestBmp,fRect,fRect,1,true);
dest.Canvas.EndScene;
finally
SrcBmp.Free;
DestBmp.Free;
end;
end;
//src画像にぼかし(平滑化、平均化)を適用してdestに作成
//(Strength:1~20)
procedure MamBlur(src,dest:FMX.Graphics.TBitmap;Strength:Integer=2);
var mn,center:Integer;
x,y,i,j,xx,yy:Integer;
fRect:TRect;
SrcBmp,DestBmp:FMX.Graphics.TBitmap;//src,destの一時画像
SrcData,DestData:TBitmapData;
SrcRGBA,DestRGBA:TRGBAArrArr;
fSRGBA:TSRGBA;
begin
if not assigned(src) then exit;
if not assigned(dest) then dest:=FMX.Graphics.TBitmap.Create;
dest.SetSize(src.Width,src.Height);
if Strength<1 then Strength:=1;
if Strength>10 then Strength:=10;
mn:=Strength*2+1;
center:=(mn-1) div 2;
fRect.Left:=0;
fRect.Top:=0;
fRect.Width:=src.Width;
fRect.Height:=src.Height;
//PixelFormatはTPixelFormat.BGRAがデフォルト
SrcBmp :=FMX.Graphics.TBitmap.Create;
DestBmp:=FMX.Graphics.TBitmap.Create;
try
SrcBmp.SetSize(fRect.Width,fRect.Height);
SrcBmp.Canvas.BeginScene();
SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,true);
SrcBmp.Canvas.EndScene;
DestBmp.SetSize(fRect.Width,fRect.Height);
//ビットマップのデータマップを取得
SrcBmp.Map(TMapAccess.Read,SrcData);
DestBmp.Map(TMapAccess.Write,DestData);
try
//スキャンラインの一括取得
for j := 0 to fRect.Height-1 do
begin
SrcRGBA[j]:=SrcData.GetScanLine(j);
DestRGBA[j]:=DestData.GetScanLine(j);
end;
for j := 0 to fRect.Height-1 do
begin
for i := 0 to fRect.Width-1 do
begin
fSRGBA.R:=0;
fSRGBA.G:=0;
fSRGBA.B:=0;
fSRGBA.A:=255;
for y := 0 to mn-1 do
begin
for x := 0 to mn-1 do
begin
yy:=j+(y-center);
if (yy<0)or(yy>=fRect.Height) then
yy:=j-(y-center);
xx:=i+(x-center);
if (xx<0)or(xx>=fRect.Width) then
xx:=i-(x-center);
fSRGBA.R:=fSRGBA.R+SrcRGBA[yy][xx].R/mn/mn;
fSRGBA.G:=fSRGBA.G+SrcRGBA[yy][xx].G/mn/mn;
fSRGBA.B:=fSRGBA.B+SrcRGBA[yy][xx].B/mn/mn;
end;
end;
if fSRGBA.R>255 then fSRGBA.R:=255;
if fSRGBA.G>255 then fSRGBA.G:=255;
if fSRGBA.B>255 then fSRGBA.B:=255;
if fSRGBA.R<0 then fSRGBA.R:=0;
if fSRGBA.G<0 then fSRGBA.G:=0;
if fSRGBA.B<0 then fSRGBA.B:=0;
DestRGBA[j][i].R:=Round(fSRGBA.R);
DestRGBA[j][i].G:=Round(fSRGBA.G);
DestRGBA[j][i].B:=Round(fSRGBA.B);
DestRGBA[j][i].A:=Round(fSRGBA.A);
end;
end;
finally
SrcBmp.Unmap(SrcData);
DestBmp.Unmap(DestData);
end;
dest.Canvas.BeginScene();
dest.Canvas.DrawBitmap(DestBmp,fRect,fRect,1,true);
dest.Canvas.EndScene;
finally
SrcBmp.Free;
DestBmp.Free;
end;
end;
//メディアンフィルタ(スパイク[ゴマ塩]ノイズの除去に有効)
//(Strength:1~4)
procedure MamMedian(src,dest:FMX.Graphics.TBitmap;Strength:Integer=1);
var mn:Integer;
Num:Integer;
x,y,i,j,xx,yy:Integer;
fRect:TRect;
SrcBmp,DestBmp,GrayBmp:FMX.Graphics.TBitmap;//src,destの一時画像
SrcData,DestData,GrayData:TBitmapData;
SrcRGBA,DestRGBA,GrayRGBA:TRGBAArrArr;
fMedian:TArray<TMedian>;
begin
if not assigned(src) then exit;
if not assigned(dest) then dest:=FMX.Graphics.TBitmap.Create;
dest.SetSize(src.Width,src.Height);
if Strength<1 then Strength:=1;
if Strength>4 then Strength:=4;
mn:=Strength*2+1;
fRect.Left:=0;
fRect.Top:=0;
fRect.Width:=src.Width;
fRect.Height:=src.Height;
//PixelFormatはTPixelFormat.BGRAがデフォルト
SrcBmp :=FMX.Graphics.TBitmap.Create;
DestBmp:=FMX.Graphics.TBitmap.Create;
GrayBmp:=FMX.Graphics.TBitmap.Create;
try
SrcBmp.SetSize(fRect.Width,fRect.Height);
SrcBmp.Canvas.BeginScene();
SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,true);
SrcBmp.Canvas.EndScene;
DestBmp.SetSize(fRect.Width,fRect.Height);
GrayBmp.SetSize(fRect.Width,fRect.Height);
MamGrayScale(SrcBmp,GrayBmp);
//ビットマップのデータマップを取得
SrcBmp.Map(TMapAccess.Read,SrcData);
DestBmp.Map(TMapAccess.Write,DestData);
GrayBmp.Map(TMapAccess.Read,GrayData);
try
//スキャンラインの一括取得
for j := 0 to fRect.Height-1 do
begin
SrcRGBA[j]:=SrcData.GetScanLine(j);
DestRGBA[j]:=DestData.GetScanLine(j);
GrayRGBA[j]:=GrayData.GetScanline(j);
end;
for j := 0 to fRect.Height-1 do
begin
for i := 0 to fRect.Width-1 do
begin
Num:=0;
for y := 0 to mn-1 do
begin
for x := 0 to mn-1 do
begin
xx:=i+x-(mn div 2);
yy:=j+y-(mn div 2);
if not ((xx<0) or
(xx>=fRect.Width) or
(yy<0) or
(yy>=fRect.Height)) then
begin
Num:=Num+1;
SetLength(fMedian,Num);
fMedian[Num-1].v:=GrayRGBA[yy][xx].R;
fMedian[Num-1].x:=xx;
fMedian[Num-1].y:=yy;
end;
end;
end;
CombSort(fMedian);
DestRGBA[j][i].R:=SrcRGBA[fMedian[Num Div 2].y][fMedian[Num Div 2].x].R;
DestRGBA[j][i].G:=SrcRGBA[fMedian[Num Div 2].y][fMedian[Num Div 2].x].G;
DestRGBA[j][i].B:=SrcRGBA[fMedian[Num Div 2].y][fMedian[Num Div 2].x].B;
DestRGBA[j][i].A:=255;
end;
end;
finally
SrcBmp.Unmap(SrcData);
DestBmp.Unmap(DestData);
GrayBmp.Unmap(GrayData);
end;
dest.Canvas.BeginScene();
dest.Canvas.DrawBitmap(DestBmp,fRect,fRect,1,true);
dest.Canvas.EndScene;
finally
SrcBmp.Free;
DestBmp.Free;
GrayBmp.Free;
end;
end;
end.
