ガンマ補正を写真画像に適用させる(FMX) ~Delphiでお手軽プログラミング

ガンマ補正を写真画像に適用させる(FMX) ~Delphiでお手軽プログラミング

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

ガンマ補正を使用する為のファイルの準備

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

プロジェクトを作成してソースコードを記述する

プロジェクトを新規作成(FMXアプリケーション)し、フォーム(Form1)にTImageを2個、TButtonを1個配置する。
Image1のPictureプロパティから、バイラテラルフィルタを適用したい画像をロードしておく。
TButton1をダブルクリックして、以下ソースコードを記述する。
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;
    procedure Button1Click(Sender: TObject);
  private
    { private 宣言 }
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses UFMXMamGamma;

procedure TForm1.Button1Click(Sender: TObject);
begin
  MamGamma(Image1.Bitmap,Image2.Bitmap,0.8);
end;

end.

実行する

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

Button1をクリックすると、Image1画像にガンマ補正が適用された画像をImage2に表示します。

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

unit UFMXMamGamma;

interface
uses System.Math,System.Types,System.UITypes, FMX.Graphics, FMX.Types;

//Strength:強さ  0.0[暗]~1.0[何もしない]~10[明]
procedure MamGamma(src,dest:FMX.Graphics.TBitmap;Strength:Single);


implementation


procedure MamGamma(src,dest:FMX.Graphics.TBitmap;Strength:Single);
Type
  TRGBA=record B,G,R,A:Byte; end;
  TRGBAArr=array[0..32767] of TRGBA;
  PRGBAArr=^TRGBAArr;
var x,y:Integer;
    fRect:TRect;
    SrcBmp,DestBmp:FMX.Graphics.TBitmap;
    SrcData,DestData:TBitmapData;
    SrcRGBA,DestRGBA:PRGBAArr;
    ChangedCol:array[0..255] of Byte;
begin
  if not Assigned(src) then exit;
  if (src.Width=0) or (src.Height=0) then exit;
  if not Assigned(dest) then
    dest:=FMX.Graphics.TBitmap.Create;

  if Strength<0 then Strength:=0;
  if Strength>10 then Strength:=10;

  fRect.Left:=0;
  fRect.Top:=0;
  fRect.Width:=src.Width;
  fRect.Height:=src.Height;
  dest.Width:=fRect.Width;
  dest.Height:=fRect.Height;

  for x:=0 to 255 do
  begin
    ChangedCol[x]:=Round(255*Power(x/255,1/Strength));
  end;

  //PixelFormatはTPixelFormat.BGRAがデフォルト
  DestBmp:=TBitmap.Create;
  SrcBmp:=TBitmap.Create;
  try
    SrcBmp.Width:=src.Width;
    SrcBmp.Height:=src.Height;
    SrcBmp.Canvas.BeginScene();
    SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,True);
    SrcBmp.Canvas.EndScene;
    DestBmp.Width:=fRect.Width;
    DestBmp.Height:=fRect.Height;

    SrcBmp.Map(TMapAccess.Read,SrcData);
    DestBmp.Map(TMapAccess.Write,DestData);
    try
      for y := 0 to fRect.Height-1 do
      begin
        SrcRGBA:=SrcData.GetScanline(y);
        DestRGBA:=DestData.GetScanline(y);
        for x := 0 to fRect.Width-1 do
        begin
          DestRGBA[x].R:=ChangedCol[SrcRGBA[x].R];
          DestRGBA[x].G:=ChangedCol[SrcRGBA[x].G];
          DestRGBA[x].B:=ChangedCol[SrcRGBA[x].B];
          DestRGBA[x].A:=SrcRGBA[x].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
    DestBmp.Free;
    SrcBmp.Free;
  end;
end;

end.