GDI+(windowsのAPI)の行列演算を使って容易に画像の変身（簡易モーフィング）を実現する

# 実行結果
![Animation3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411106/39e48f71-cabb-e2c6-9565-c4162d3ee7bf.gif)

# 解説
画像は点（ドット）の集まりで構成されていて、その各ドットの色要素が(RGBα)の場合、α(透過度)を徐々に変化させれば徐々に透けていく絵が表示できます。
2つの画像を用意して、一方はαの値を255→0(無透過→透明)、もう一方を0→255(透明→無透過)に徐々に変化させ、この2つの画像を重ね合わせれば、画像の変身（簡易モーフィング）が実現します。

GDI+を使えば、画像を構成するすべてのドットのα値の変更を簡単に実現させることができます。
その方法は以下の行列式の演算で行えます。
```math
\begin{pmatrix}
R,& G,& B,& α,& 1
\end{pmatrix}
\begin{pmatrix}
1,&0,&0,&0,&0 \\
0,&1,&0,&0,&0 \\
0,&0,&1,&0,&0 \\
0,&0,&0,&透過率,&0 \\
0,&0,&0,&0,&1 \\
\end{pmatrix}
＝＞
\begin{pmatrix}
R,& G,& B,& α \times 透過率,&　1
\end{pmatrix}
```
詳しくは以下の記事が参考になります。

http://mrxray.on.coocan.jp/Delphi/GDIPlusSamples/G022_GDIPlus_ColorMatrix.htm


# プログラム
Delphiでコーディングしたら以下のようになります
[参考元](http://blog.livedoor.jp/junki560/archives/22456765.html)

```delphi
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, GDIPOBJ, GDIPAPI;

type
  TForm1 = class(TForm)
    Image1: TImage;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Image1Click(Sender: TObject);
  private
    FGPBitmap: array[1..2] of TGPBitmap;
    procedure Image1Paint(Count: Integer);
  public
    { Public 宣言 }
  end;

const
  FILE1 = 'z:\file1.jpg';
  FILE2 = 'z:\file2.jpg';
  WAITTIME = 10; //1回ごとのウェイトタイム（ミリ秒）
  TIMES = 100;   //変身までに何回描画するか

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FGPBitmap[1] := TGPBitmap.Create(FILE1);
  FGPBitmap[2] := TGPBitmap.Create(FILE2);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FGPBitmap[1]);
  FreeAndNil(FGPBitmap[2]);
end;

procedure TForm1.Image1Click(Sender: TObject);
begin
  for var i := 0 to TIMES do begin
    Image1Paint(i);
    Image1.Repaint;
    Sleep(WAITTIME);
  end;
  var swap := FGPBitmap[1];
  FGPBitmap[1] := FGPBitmap[2];
  FGPBitmap[2] := swap;
end;

procedure TForm1.Image1Paint(Count: Integer);
const
  CM_DEFAULT : TColorMatrix = (
      (1, 0, 0, 0, 0),
      (0, 1, 0, 0, 0),
      (0, 0, 1, 0, 0),
      (0, 0, 0, 1, 0),
      (0, 0, 0, 0, 1));
var
  gcanvas: TGPGraphics;
  cm: TColorMatrix;
  ia: TGPImageAttributes;
begin
  var w := FGPBitmap[1].GetWidth;
  var h := FGPBitmap[1].GetHeight;

  ia := TGPImageAttributes.Create;
  gcanvas := TGPGraphics.Create(Image1.Canvas.Handle);

  cm := CM_DEFAULT;

  cm[3,3] := Count / TIMES;
  ia.SetColorMatrix(cm);
  gcanvas.DrawImage(FGPBitmap[1],
                    MakeRect(0, 0, w, h),
                    0, 0,
                    w, h,
                    UnitPixel,
                    ia);

  cm[3,3] := 1 - cm[3,3];
  ia.SetColorMatrix(cm);
  gcanvas.DrawImage(FGPBitmap[2],
                    MakeRect(0, 0, w, h),
                    0, 0,
                    w, h,
                    UnitPixel,
                    ia);

  FreeAndNil(gcanvas);
  FreeAndNil(ia);
end;
end.
```
Githubにソースがあります。

https://github.com/takanaweb5/GDIPlus-morphing2


# あとがき
GDI+を使えば、複雑な画像の回転・拡大縮小などを行うアフィン変換も容易に実現できるようです。

https://qiita.com/koshian2/items/c133e2e10c261b8646bf