Homography.png

 

Homography.zip @ Delphi XE7 Update1 

 

カメラで机の上の書類などを斜めから撮ると、遠近法的にパースが掛かって、矩形の画像とはなってくれません。

しかしこの座標変換を使うと、パースの掛かった画像から、本来の矩形画像を切り出すことが出来ます。

もっともそのためにはソース画像上で、切り出すエリアの4隅の座標を指定する必要があります。

 

今回その座標変換を THomography というクラスにまとめました。

生成時に 左上/右上/左下/右下 の順で切り出すエリアを指定できますし、

_Trans := THomography.Create(
          TPointF.Create( 270, 176 ), TPointF.Create( 488, 203 ),
          TPointF.Create(  66, 302 ), TPointF.Create( 229, 433 ) );

 生成後に四隅座標を指定し直すことも出来ます。

_Trans.Poin00 := TPointF.Create( X, Y ); :左上
_Trans.Poin01 := TPointF.Create( X, Y ); :右上
_Trans.Poin10 := TPointF.Create( X, Y ); :左下
_Trans.Poin11 := TPointF.Create( X, Y ); :右下

そして、実際に画像の切り出しを行っているのが以下の部分。

procedure TForm1.Cutout;
var
   B :TBitmapData;
begin
     Image2.Bitmap.Map( TMapAccess.Write, B );

     TParallel.For( 0, 512-1, procedure( Y:Integer )
     var
        X :Integer;
        P, S :TPointF;
        C :PAlphaColor;
     begin
          P.Y := ( Y + 0.5 ) / 512;

          C := B.GetScanline( Y );

          for X := 0 to 512-1 do
          begin
               P.X := ( X + 0.5 ) / 512;

               if _Trans.ToScreen( P, S ) then C^ := GetMapColor( S )
                                          else C^ := TAlphaColorRec.Null;

               Inc( C );
          end;
     end );

     Image2.Bitmap.Unmap( B );
end;

TParallel.For を用いてマルチスレッド化されていますが、やっていることは、切出先画像 のピクセル(中心座標P)を走査していって、それに対応する 切出元画像 のピクセル(座標S)の色を取ってきているだけです。座標変換を行っているのが以下のメソッドですが、

THomography.ToScreen( const P_:切出先画像の座標; var S_:切出元画像の座標 ) :変換成功;

四隅座標の取り方によっては変換できない場合があるので、戻り値としては変換が成功したかどうかの真偽値を返します。成功した場合は、 S_ に切出元画像上での座標が返ります。

もっとも、P は整然と切出先画像のピクセル中心に対応しますが、それから変換された S は切出元画像のピクセルに対応していません。なので本来は何らかの補間を施すべきですが、今回はニアレストネイバー法でお茶を濁しました。