バイキュービック法(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.
