Visual Basic でOpenCV⑪ - アフィン変換

Visual BasicOpenCVを使ったプログラムを紹介します。単純な座標変換プログラムを紹介します。

アフィン変換

単純な座標変換プログラムを紹介します。ユーザーインターフェースなどはこれまでと同じです。

フリップ

Visual BasicOpenCVのプログラムと異なるのはプロジェクト名を変更した1行のみです。具体的には、「Imports Sample.CCvLibrary」のように、クラスの名前空間のImportsが変わるだけです。先のプログラムのプロジェクト名は「Filters」でしたが、これ以降はプロジェクト名を「Sample」とします。自身で新たに名前空間を定義したときは、クラスの名前空間の前にプロジェクト名を指定します。つまり、「Imports」の指定は「"アセンブリ名".名前空間」です。通常、アセンブリ名とプロジェクト名は一致します。

CCvFunc.vb

フォームのコードは「Imports」が異なるだけで、残りは先のプログラムと同じです。このため、フォームなどのソースリストは示さず、派生クラスのCCvFunc.vbのソースリストのみを示します。

Imports OpenCvSharp

Namespace CCvLibrary
    Public Class CCvFunc
        Inherits CCv
        '----------------------------------------------------------------
        'コンストラクタ
        Public Sub New()
            MyBase.New()
        End Sub

        '----------------------------------------------------------------
        ' OpenCVを使用して処理
        Public Function DoCvFunction() As System.Drawing.Bitmap
            mDst = New Mat()
            Cv2.Flip(mSrc, mDst, FlipMode.X)    ' x 軸周りでの反転(上下反転)
            Return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mDst)
        End Function

    End Class
End Namespace

画像のフリップはCv2.Flip メソッドで行います。まず、変換後の画像を保持するmDst フィールドをインスタンス化します。どのようにフリップするかは、引数によって変わります。次に、Cv2.Flip メソッドに入力画像、変換後の画像を格納するMat オブジェクト、そしてフリップの方法を示すフラグを指定します。最後に、変換した画像をBitmap オブジェクトへ変換して、呼び出し元へ返します。
この例では、フリップのフラグにFlipMode.X を指定し、x 軸周りでの反転(上下反転)を行います。

実行

実行例を示します。プログラムを起動し、[ファイル]-[開く]を選択し、読み込む画像を指定します。画像を読み込むと、自動でウィンドウが画像を表示できるサイズに変更されます。[ツール]-[処理]を選択し、画像をフリップします。

y 軸周りでの反転(左右反転)したい場合は以下のように、
Cv2.Flip(mSrc, mDst, FlipMode.Y)
第二引数にFlipMode.Yを指定します。

左右が比較的対称な画像を選んだため分かりにくいです。両軸周りで反転したい場合は以下のように、
Cv2.Flip(mSrc, mDst, FlipMode.XY)
第二引数にFlipMode.XYを指定します。

リサイズ

画像をリサイズするプログラムを紹介します。

CCvFunc.vb

先のプログラムと異なるのはCCvFunc.vbのDoCvFunction メソッドのみですので、その部分だけ示します。

        :
        Public Function DoCvFunction() As System.Drawing.Bitmap
            mDst = New Mat()
            Cv2.Resize(mSrc, mDst, New OpenCvSharp.Size(), 0.5, 0.5)
            Return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mDst)
        End Function
        :

画像のリサイズはCv2.Resize メソッドで行います。拡大縮小は、第4 引数、第5 引数に倍率を与えることによって指定します。サイズ変更時の補間は、デフォルトのバイリニア補間が使われます。この例では、縦横ともに元の画像を0.5 倍、つまり、元の画像の半分の大きさに縮小します。以降に、実行結果を示します。

実行

回転

画像を回転するプログラムを紹介します。

CCvFunc.vb

CCvFunc.cs のDoCvFunction メソッドのみを示します。

        :
        Public Function DoCvFunction() As System.Drawing.Bitmap
            mDst = New Mat()
            Dim center As New Point2f(mSrc.Cols / 2, mSrc.Rows / 2)
            Dim angle As Single = 33.3F
            Dim affineTrans As Mat = Cv2.GetRotationMatrix2D(center, angle, 1.0)
            Cv2.WarpAffine(mSrc, mDst, affineTrans, mSrc.Size(), InterpolationFlags.Cubic)
            Return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mDst)
        End Function
        :

回転はCv2.GetRotationMatrix2Dメソッドの引数に回転の原点、回転角度、そしてスケーリング値を指定し、得られた行列をCv2.WarpAffineメソッドへ与えます。
まず、Point2f のcenterへ画像の中心座標を設定します。次に、floatのangle へ回転角度を格納します。回転そのものは、Cv2.WarpAffineメソッドで行います。Cv2.WarpAffineメソッドは引数に、2×3の行列を渡すことによって回転処理を行います。この2×3の行列を得るために、Cv2.GetRotationMatrix2Dメソッドの引数に回転の原点、回転角度、そしてスケーリング値を指定します。すると、画像回転に使用する2×3の2次元回転のアフィン変換行列を取得できます。MatオブジェクトaffineTransは、スケーリング値が1.0、回転角度がθ、そして原点が (Xa, Ya) の場合、以下のような値が設定されます。

θ は反時計方向への回転角度です。
実際の回転はCv2.WarpAffine メソッドで行います。上記の行列式から、任意の点 (Xa, Ya) を中心に、(x, y) を θ だけ反時計方向に回転したときの新しい座標(X, Y ) は、次の式で表すことができます。これは順方向です。

逆変換は次の式で表すことができます。画像を回転させるということは、出力画像の各ピクセル値を入力画像中のピクセルから以下の式に従ってサンプリングすることと等価です。

Cv2.WarpAffine メソッドは、スケーリングや補間方法も指定できるため、実際はもっと複雑な処理を行っています。

実行

以降に、実行結果を示します。

透視投影

画像へ透視投影を行うプログラムを紹介します。

CCvFunc.vb

これまでと異なるCCvFunc.cs のDoCvFunction メソッドのみを示します。

        :
        Public Function DoCvFunction() As System.Drawing.Bitmap
            Dim x0 As Single = CSng(mSrc.Cols / 4)
            Dim x1 As Single = CSng((mSrc.Cols / 4) * 3)
            Dim y0 As Single = CSng(mSrc.Rows / 4)
            Dim y1 As Single = CSng((mSrc.Rows / 4) * 3)
            Dim srcPoint As Point2f() = {New Point2f(x0, y0),
                New Point2f(x0, y1), New Point2f(x1, y1), New Point2f(x1, y0)}
            Dim dstPoint As Point2f() = New Point2f(3) {}
            Dim xMergin As Integer = mSrc.Cols / 10
            Dim yMergin As Integer = mSrc.Rows / 10
            dstPoint(0) = New Point2f(x0 + xMergin, y0 + yMergin)
            dstPoint(1) = srcPoint(1)
            dstPoint(2) = srcPoint(2)
            dstPoint(3) = New Point2f(x1 - xMergin, y0 + yMergin)
            Dim perspectiveMmat As Mat = Cv2.GetPerspectiveTransform(srcPoint, dstPoint)
            mDst = New Mat()
            Cv2.WarpPerspective(mSrc, mDst, perspectiveMmat, mSrc.Size(), InterpolationFlags.Cubic)
            Return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mDst)
        End Function
        :

本プログラムは、固定の透視投影を行います。透視投影の座標を図に示します。

座標をCv2.GetPerspectiveTransform メソッドへ与えMat オブジェクトを求めます。それをCv2.WarpPerspective メソッドの引数に使用し、透視投影変換を行います。

実行

以降に、実行結果を示します。