バイキュービック法(bicubic)で画像を拡大縮小(FMX) ~Delphiソースコード集
(参考)バイキュービック法(bicubic)で拡大縮小する(VCL)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(VCL)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(FMX)
(参考)ソーベルフィルタ(Sobel filter)で境界(エッジ)検出(VCL)
バイキュービック法を使用する為のファイルの準備
本ページの下部のソースコードをコピーして「UFMXMamBicubic.pas」ファイルを作成し、 プロジェクトフォルダ内に入れる。ソースコードの記述
プロジェクトを新規作成(FMXアプリケーション)し、フォーム(Form1)にTImageを2個、TButtonを1個配置する。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; Button1: TButton; Image2: TImage; procedure Button1Click(Sender: TObject); private { private 宣言 } public { public 宣言 } end; var Form1: TForm1; implementation {$R *.fmx} uses FMX.Utils,UFMXMamBicubic; procedure TForm1.Button1Click(Sender: TObject); begin Image2.Bitmap.Width :=Trunc(Image1.Bitmap.Width * 1.4); Image2.Bitmap.Height:=Trunc(Image1.Bitmap.Height * 1.4); MamBicubic( Image1.Bitmap, Image2.Bitmap, TMamBicubicType.Bicubic4x4 ); end; end.
実行する
実行ボタンを押して実行します。(デバッグ実行でもOK)Button1をクリックすると、Image1写真画像をバイキュービック法で拡大した画像をImage2に表示します。
「UFMXMamBicubic.pas」ファイルのソースコード
unit UFMXMamBicubic; interface uses System.Types,System.UITypes, FMX.Graphics, FMX.Types; Type TMamBicubicType=(Bicubic4x4,Bicubic6x6); procedure MamBicubic(src,dest:FMX.Graphics.TBitmap; BicubicType:TMamBicubicType=TMamBicubicType.Bicubic4x4); implementation Type TSRGBA=record B,G,R,A:Single; end; TRGBA=record B,G,R,A:Byte; end; TRGBAArr=array[0..32767] of TRGBA; PRGBAArr=^TRGBAArr; TRGBAArrArr=array[0..32767] of PRGBAArr; //PRGBAArrArr=^TRGBAArrArr; //バイキュービック4x4の距離による重み定数 Function MamBicubicWeight4x4(d:Single):Single; const a:Single=-1.0; //シャープの強さ -0.5(弱) ~ -1.0(強)の値を与える begin if d<0 then begin result:=0; end else if d<=1 then result:= (a+2)*d*d*d - (a+3)*d*d + 1 else if d<=2 then result:= a*d*d*d - 5*a*d*d + 8*a*d - 4*a else result:=0; end; //バイキュービック6x6の距離による重み定数 Function MamBicubicWeight6x6(d:Single):Single; begin if d<0 then begin result:=0; end else if d<=1 then result:= 4*d*d*d/3 - 7*d*d/3 + 1 else if d<2 then result:= -7*d*d*d/12 + 3*d*d - 59*d/12 + 5/2 else if d<3 then result:= d*d*d/12 - 2*d*d/3 + 7*d/4 - 3/2 else result:=0; end; procedure MamBicubic(src,dest:FMX.Graphics.TBitmap; BicubicType:TMamBicubicType=TMamBicubicType.Bicubic4x4); var SrcBmp,DestBmp:TBitmap;//src,destの一時画像 fRect:TRect; SrcData,DestData:TBitmapData; SrcRGBA,DestRGBA:TRGBAArrArr; RatioWidth,RatioHeight:Single; Dimension:Integer; x,y,dx,dy:Integer; sx,sy:Single; //destからsourceへの変換後 x,y座標の小数 tsx,tsy:Integer;//destからsourceへの変換後 x,y座標の整数 tsxx,tsyy:Integer; sum:Single; Weight:Single; //Bicubicの重みづけ定数 WeightMatrix:array of array of Single;//4x4又は6x6の重みづけ定数配列 fRGBA:TSRGBA; begin if not assigned(src) then exit; if not assigned(dest) then exit; RatioWidth :=src.Width /dest.Width ; RatioHeight:=src.Height/dest.Height; //Bicubicの4x4か6x6か if BicubicType=TMamBicubicType.Bicubic4x4 then Dimension:=4 else Dimension:=6; //距離の重み定数配列を初期化 setlength(WeightMatrix,Dimension); for x := 0 to Dimension-1 do setlength(WeightMatrix[x],Dimension); //PixelFormatはTPixelFormat.BGRAがデフォルト DestBmp:=TBitmap.Create; SrcBmp:=TBitmap.Create; try SrcBmp.Width:=src.Width; SrcBmp.Height:=src.Height; fRect.Left:=0; fRect.Top:=0; fRect.Width:=src.Width; fRect.Height:=src.Height; SrcBmp.Canvas.BeginScene(); SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,True); SrcBmp.Canvas.EndScene; DestBmp.Width:=dest.Width; DestBmp.Height:=dest.Height; SrcBmp.Map(TMapAccess.Read,SrcData); DestBmp.Map(TMapAccess.Write,DestData); try for y := 0 to SrcBmp.Height-1 do begin SrcRGBA[y]:=SrcData.GetScanline(y); end; for y := 0 to DestBmp.Height-1 do begin DestRGBA[y]:=DestData.GetScanline(y); end; for dy := 0 to DestBmp.Height-1 do begin for dx := 0 to DestBmp.Width-1 do begin sx:=dx*RatioWidth; sy:=dy*RatioHeight; tsx:=trunc(sx); tsy:=trunc(sy); fRGBA.R:=0; fRGBA.G:=0; fRGBA.B:=0; sum:=0; //重み定数の取得 for y := 0 to Dimension-1 do begin for x := 0 to Dimension-1 do begin tsxx:=tsx+x-(Dimension div 2 -1); tsyy:=tsy+y-(Dimension div 2 -1); if not((tsxx<0) or (tsxx>=SrcBmp.Width) or (tsyy<0) or (tsyy>=SrcBmp.Height)) then begin if Dimension=4 then Weight:=MamBicubicWeight4x4( sqrt((tsxx-sx)*(tsxx-sx)+(tsyy-sy)*(tsyy-sy)) ) else Weight:=MamBicubicWeight6x6( sqrt((tsxx-sx)*(tsxx-sx)+(tsyy-sy)*(tsyy-sy)) ); WeightMatrix[x,y]:=Weight; sum:=sum+Weight; end; end; end; //バイキュービックの実行 for y := 0 to Dimension-1 do begin for x := 0 to Dimension-1 do begin tsxx:=tsx+x-(Dimension div 2 -1); tsyy:=tsy+y-(Dimension div 2 -1); if not((tsxx<0) or (tsxx>=fRect.Width) or (tsyy<0) or (tsyy>=fRect.Height)) then begin WeightMatrix[x,y]:=WeightMatrix[x,y]/sum; fRGBA.R:=fRGBA.R+srcRGBA[tsyy][tsxx].R*WeightMatrix[x,y]; fRGBA.G:=fRGBA.G+srcRGBA[tsyy][tsxx].G*WeightMatrix[x,y]; fRGBA.B:=fRGBA.B+srcRGBA[tsyy][tsxx].B*WeightMatrix[x,y]; end; end; end; if fRGBA.R>255 then fRGBA.R:=255; if fRGBA.G>255 then fRGBA.G:=255; if fRGBA.B>255 then fRGBA.B:=255; if fRGBA.R<0 then fRGBA.R:=0; if fRGBA.G<0 then fRGBA.G:=0; if fRGBA.B<0 then fRGBA.B:=0; fRGBA.A:=255; DestRGBA[dy][dx].R:=Round(fRGBA.R); DestRGBA[dy][dx].G:=Round(fRGBA.G); DestRGBA[dy][dx].B:=Round(fRGBA.B); DestRGBA[dy][dx].A:=Round(fRGBA.A); end; end; finally SrcBmp.Unmap(SrcData); DestBmp.Unmap(DestData); end; fRect.Left:=0; fRect.Top:=0; fRect.Width:=dest.Width; fRect.Height:=dest.Height; dest.Canvas.BeginScene(); dest.Canvas.DrawBitmap(DestBmp,fRect,fRect,1,True); dest.Canvas.EndScene; finally SrcBmp.Free; DestBmp.Free; end; end; end.