明るさ(Bright)コントラスト(Contrast)補正を写真画像に適用させる(FMX) ~Delphiでお手軽プログラミング

明るさ(Bright)コントラスト(Contrast)補正を写真画像に適用させる(FMX) ~Delphiでお手軽プログラミング

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

明るさ、コントラスト補正を使用する為のファイルの準備

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

プロジェクトの作成とソースコードの記述

プロジェクトを新規作成(FMXアプリケーション)し、フォーム(Form1)にTImageを2個、TTrackBarを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;
    TrackBar1: TTrackBar;
    TrackBar2: TTrackBar;
    Label1: TLabel;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { private 宣言 }
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses UFMXMamBrightContrast;

procedure TForm1.Button1Click(Sender: TObject);
var bmp:FMX.Graphics.TBitmap;
begin
  bmp:=FMX.Graphics.TBitmap.Create;
  try
    //Image1の明るさを調整してbmpに
    MamBright(Image1.Bitmap, bmp, TrackBar1.Value);
    //bmpのコントラストを調整してImage2に
    MamContrast(bmp, Image2.Bitmap, TrackBar2.Value);
  finally
    bmp.Free
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //明るさ調整
  TrackBar1.Min:=-1;
  TrackBar1.Max:=1;
  TrackBar1.Value:=0;

  //コントラスト調整
  TrackBar2.Min:=-1;
  TrackBar2.Max:=1;
  TrackBar2.Value:=0;

end;

end.

実行する

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

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

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

unit UFMXMamBrightContrast;

interface

uses System.Types,System.UITypes, System.Math,
     System.Generics.Collections, System.Generics.Defaults,
     FMX.Graphics, FMX.Types;

//使い方 MamContrast(変換元TBitmap,変換後TBitmap,強さ[-1.0~+1.0])
procedure MamContrast(src,dest:FMX.Graphics.TBitmap;Strength:Single=0.0);
//使い方 MamContrast(変換元TBitmap,変換後TBitmap,強さ[-1.0~+1.0])
procedure MamBright(src,dest:FMX.Graphics.TBitmap;Strength:Single=0.0);


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;

procedure MamContrast(src,dest:FMX.Graphics.TBitmap;Strength:Single=0.0);
var v:byte;
    x,y:Integer;
    r,g,b:Integer;
    fRect:TRect;
    SrcBmp,DestBmp:TBitmap;//src,destの一時画像
    SrcData,DestData:TBitmapData;
    SrcRGBA,DestRGBA:PRGBAArr;
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> 1 then Strength:= 1;
  if Strength<-1 then Strength:=-1;
  Strength:=Strength+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;
  try
    SrcBmp.Width :=fRect.Width;
    SrcBmp.Height:=fRect.Height;
    SrcBmp.Canvas.BeginScene();
    SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,true);
    SrcBmp.Canvas.EndScene;
    DestBmp.Width:=fRect.Width;
    DestBmp.Height:=fRect.Height;
    dest.Width:=fRect.Width;
    dest.Height:=fRect.Height;

    SrcBmp.Map(TMapAccess.Read,SrcData);
    DestBmp.Map(TMapAccess.Write,DestData);
    try
      v:=127;

      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
          r:=Round((SrcRGBA[x].R-v)*Strength+v);
          g:=Round((SrcRGBA[x].G-v)*Strength+v);
          b:=Round((SrcRGBA[x].B-v)*Strength+v);
          if r>255 then r:=255;
          if g>255 then g:=255;
          if b>255 then b:=255;
          if r<0 then r:=0;
          if g<0 then g:=0;
          if b<0 then b:=0;

          DestRGBA[x].R:=r;
          DestRGBA[x].G:=g;
          DestRGBA[x].B:=b;
          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;


procedure MamBright(src,dest:FMX.Graphics.TBitmap;Strength:Single=0.0);
var x,y:Integer;
    r,g,b:Integer;
    fRect:TRect;
    SrcBmp,DestBmp:TBitmap;//src,destの一時画像
    SrcData,DestData:TBitmapData;
    SrcRGBA,DestRGBA:PRGBAArr;
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;
  fRect.Left:=0;
  fRect.Top:=0;
  fRect.Width:=src.Width;
  fRect.Height:=src.Height;

  if Strength> 1 then Strength:= 1;
  if Strength<-1 then Strength:=-1;
  Strength:=Strength*127;

  SrcBmp:=FMX.Graphics.TBitmap.Create;
  DestBmp:=FMX.Graphics.TBitmap.Create;
  try
    SrcBmp.Width :=fRect.Width;
    SrcBmp.Height:=fRect.Height;
    SrcBmp.Canvas.BeginScene();
    SrcBmp.Canvas.DrawBitmap(src,fRect,fRect,1,True);
    SrcBmp.Canvas.EndScene;
    DestBmp.Width:=fRect.Width;
    DestBmp.Height:=fRect.Height;
    dest.Width:=fRect.Width;
    dest.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
          r:=Round(SrcRGBA[x].R+Strength);
          g:=Round(SrcRGBA[x].G+Strength);
          b:=Round(SrcRGBA[x].B+Strength);
          if r>255 then r:=255;
          if g>255 then g:=255;
          if b>255 then b:=255;
          if r<0 then r:=0;
          if g<0 then g:=0;
          if b<0 then b:=0;

          DestRGBA[x].R:=r;
          DestRGBA[x].G:=g;
          DestRGBA[x].B:=b;
          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;

end.