トップへ(mam-mam.net/)

バイキュービック法(bicubic)で画像を拡大縮小(VCL) ~Delphiソースコード集

検索:

バイキュービック法(bicubic)で画像を拡大縮小(VCL) ~Delphiソースコード集

(参考)バイキュービック法(bicubic)で拡大縮小する(FMX)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(VCL)
(参考)バイラテラルフィルタ(bilateral filter)で美肌に加工(FMX)
(参考)ソーベルフィルタ(Sobel filter)で境界(エッジ)検出(VCL)

バイキュービック法を使用する為のファイルの準備

本ページの下部のソースコードをコピーして「UMamBicubic.pas」ファイルを作成し、 プロジェクトフォルダ内に入れる。

ソースコードの記述

プロジェクトを新規作成(VCLアプリケーション)し、フォーム(Form1)にTImageを2個、TButtonを1個配置する。
Image1のPictureプロパティから、バイキュービック法で拡大縮小を適用したい画像をロードしておく。
TButton1をダブルクリックして、以下ソースコードを記述する。
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Imaging.jpeg,
  Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses UMamBicubic;

procedure TForm1.Button1Click(Sender: TObject);
var bmp,sbmp,dbmp:TBitmap;
begin
  bmp:=TBitmap.Create;
  bmp.Assign(Image1.Picture.Graphic);
  Image2.Picture.Bitmap.Width:=400;  //リサイズする幅
  Image2.Picture.Bitmap.Height:=400; //リサイズする高さ
  MamBicubic(bmp,Image2.Picture.Bitmap,TMamBicubicType.Bicubic4x4);
  bmp.free;
end;

end.

実行する

実行ボタンを押して実行します。(デバッグ実行でもOK)

Button1をクリックすると、Image1写真画像をバイキュービック法で拡大縮小した画像をImage2に表示します。

「UMamBicubic.pas」ファイルのソースコード

unit UMamBicubic;

interface
uses Vcl.Graphics,System.Math;

Type
  TMamBicubicType=(Bicubic4x4,Bicubic6x6);

procedure MamBicubic(source,dest:TBitmap;
  BicubicType:TMamBicubicType=TMamBicubicType.Bicubic4x4);


implementation

Type
  TRRGB=record B,G,R:Extended; end;
  TRGB =record B,G,R:byte; end;
  TRGBArr=array[0..32767] of TRGB;
  PRGBArr=^TRGBArr;
  TRGBArrArr=array[0..32767] of PRGBArr;


//バイキュービック4x4の距離による重み定数
Function MamBicubicWeight4x4(d:Extended):Extended;
const a:Extended=-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:Extended):Extended;
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;

//sourceをdestに拡大縮小する。
//適用後画像サイズはdest.width,dest.heightに事前に設定しておく
procedure MamBicubic(source,dest:TBitmap;
  BicubicType:TMamBicubicType=TMamBicubicType.Bicubic4x4);
var sw,sh:Extended;//拡大率縮小率
    dx,dy:Integer;//dest x,y座標
    sx,sy:Extended;//destからsourceへの変換後 x,y座標の小数
    tsx,tsy:Integer;//destからsourceへの変換後 x,y座標の整数
    tsxx,tsyy:Integer;
    x,y:Integer;
    w:Extended; //BicubicのWeight
    rrgb:TRRGB;
    m:array of array of Extended;//4x4 or 6x6
    mn:Integer; //4 or 6
    saa,daa:TRGBArrArr;
    sum:Extended;
begin
  if not Assigned(source) then exit;
  if not Assigned(dest) then exit;
  source.PixelFormat:=pf24bit;
  dest.PixelFormat:=pf24bit;

  sw:=source.Width /dest.Width ;
  sh:=source.Height/dest.Height;

  for y := 0 to source.Height-1 do
    saa[y]:=source.ScanLine[y];
  for y := 0 to dest.Height-1 do
    daa[y]:=dest.ScanLine[y];

  if BicubicType=TMamBicubicType.Bicubic4x4 then
    mn:=4
  else
    mn:=6;

  setlength(m,mn);
  for x := 0 to mn-1 do
    setlength(m[x],mn);

  for dy := 0 to dest.Height-1 do
  begin
    for dx := 0 to dest.Width-1 do
    begin
      sx:=dx*sw;
      sy:=dy*sh;
      tsx:=trunc(sx);
      tsy:=trunc(sy);
      rrgb.R:=0;
      rrgb.G:=0;
      rrgb.B:=0;
      sum:=0;
      for y := 0 to mn-1 do
      begin
        for x := 0 to mn-1 do
        begin
          tsxx:=tsx+x-(mn div 2 -1);
          tsyy:=tsy+y-(mn div 2 -1);
          if not((tsxx<0) or (tsxx>=source.Width) or
             (tsyy<0) or (tsyy>=source.Height)) then
          begin
            if mn=4 then
              w:=MamBicubicWeight4x4(
                sqrt((tsxx-sx)*(tsxx-sx)+(tsyy-sy)*(tsyy-sy))
              )
            else
              w:=MamBicubicWeight6x6(
                sqrt((tsxx-sx)*(tsxx-sx)+(tsyy-sy)*(tsyy-sy))
              );
            m[x,y]:=w;
            sum:=sum+w;
          end;
        end;
      end;
      for y := 0 to mn-1 do
      begin
        for x := 0 to mn-1 do
        begin
          tsxx:=tsx+x-(mn div 2 -1);
          tsyy:=tsy+y-(mn div 2 -1);
          if not((tsxx<0) or (tsxx>=source.Width) or
             (tsyy<0) or (tsyy>=source.Height)) then
          begin
            m[x,y]:=m[x,y]/sum;
            rrgb.R:=rrgb.R+saa[tsyy,tsxx].R*m[x,y];
            rrgb.G:=rrgb.G+saa[tsyy,tsxx].G*m[x,y];
            rrgb.B:=rrgb.B+saa[tsyy,tsxx].B*m[x,y];
          end;
        end;
      end;
      if rrgb.R>255 then rrgb.R:=255;
      if rrgb.G>255 then rrgb.G:=255;
      if rrgb.B>255 then rrgb.B:=255;
      if rrgb.R<0 then rrgb.R:=0;
      if rrgb.G<0 then rrgb.G:=0;
      if rrgb.B<0 then rrgb.B:=0;
      daa[dy,dx].R:=round(rrgb.R);
      daa[dy,dx].G:=round(rrgb.G);
      daa[dy,dx].B:=round(rrgb.B);
    end;
  end;
end;

end.