OpenCvSharp4を使ってみよう

Page content

Schimaさんが作成されているOpenCVの.NET用ラッパー、「OpenCVSharp」のバージョン4を触ってみましょうということで。(Windows用、また私が実際に使用している関数しか触れない+言語はVB.NETです。プログラミングの知識もないのでメチャクチャなところもあると思います。予めご了承下さい。)

インストール

VisualStudioで新しくプロジェクトを作り、「プロジェクト」→「NuGetパッケージの管理」を開きます。 参照タブを開いて「opencvsharp4」で検索すると4つほどOpenCvSharp4関連のパッケージが出てきます。今回はWindows用のパッケージを入れるので、「OpenCvSharp4.runtime.win」をインストール。計3つのパッケージがインストールされます。

(↓の操作は不要かもしれません) 次に、作成したプロジェクトのあるディレクトリにある、「OpenCvSharpExtern.dll」 “[project]\packages\OpenCvSharp4.runtime.win.4.0.0.xx\runtimes\win-x64\native\OpenCvSharpExtern.dll” を、VisualStudioのソリューションエクスプローラーにD&Dします。

「OpenCvSharpExtern.dll」をクリックしてプロパティを開き、出力ディレクトリにコピーを「新しい場合はコピーする」に変更します。

今回は64bitバージョンを入れたので、64bitで実行されるようにします。 プロジェクト→[プロジェクト名]のプロパティを開き、コンパイルタブにある「32ビットを優先」のチェックを外します。 32bitバージョンを使用する場合は変更しなくてもいけるかと思います。いけなかったら、構成マネージャーを開いて、アクティブソリューションプラットフォームをAny CPUからx86(新規作成、コピー元をAny CPUで作成する)にしてみて下さい。

これでOpenCVSharopが使えるようになるはずです。

使用

コードに「Imports OpenCvSharp」を書いて使用可能状態に。画像処理のライブラリなので、画像を読み込んで処理/表示し、保存する、という流れが基本になると思います。

画像の読み込み

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.Color)
        Cv2.ImShow("test", img)
        Cv2.WaitKey()
    End Using

End Sub

OpenCVでは画像はMatという形式で処理されます。そのため、表示も専用のウィンドウを使用する必要があります。 ImreadModesを変更するとグレースケールで読み込んだりすることもできます。画像処理はグレースケール化して行うことが多いので、読み込み時点でグレースケール化すると楽ちんですね。

Windowsフォームに表示したい場合は、読み込んだ画像をBitmapconverterでBitmapに変換して、PictureBoxで表示させます。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

     Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.AnyColor)

            PictureBox1.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(img)

     End Using

End Sub

もしくは、PictureBoxIplを使用します(Matと混合利用することは管理面で推奨されないのでしょうが、お手軽に表示できるのでつい利用してしまう…いずれ消失する可能性があるので、その点でもおすすめできません。)

PictureBoxIplは、ツールボックス欄を右クリック→「アイテムの選択」をクリックし、ウィンドウが出たら.NET Frameworkタブの参照をクリック、 “[project名]\packages\OpenCvSharp4.4.0.0.xx\lib\net461\OpenCvSharp.Extensions.dll”を追加すると出てきます。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

     Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.AnyColor)

            PictureBoxIpl1.ImageIpl = img

     End Using

End Sub

画像の読み込みは以上。

画像処理(クロップ、リサイズ、グレースケール化、2値化、エッジ化)

この辺りはどんな処理をするときも必要になる…んでしょうかね?

クロップ(Rect)

     Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.AnyColor)
            Using dst = New Mat(img, New OpenCvSharp.Rect(X座標, Y座標, 幅, 高さ))
            
                  PictureBoxIpl1.ImageIpl = dst

            End Using
     End Using

リサイズ(Cv2.Resize)

     Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.AnyColor)
           Using dst As New Mat()
                Cv2.Resize(img, dst, New OpenCvSharp.Size(320, 180), interpolation:= InterpolationFlags.Lanczos4)
                PictureBoxIpl1.ImageIpl = dst
                  
           End Using
     End Using
    Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.AnyColor)
           Using dst As New Mat()
                Cv2.Resize(img, matresize, New OpenCvSharp.Size, 2, 0.5, interpolation:=InterpolationFlags.Lanczos4)
                PictureBoxIpl1.ImageIpl = dst
                  
           End Using
     End Using

上はサイズを指定してリサイズ、下は縦横を倍率指定してリサイズします。 Interpolation…リサイズメソッドは未指定だとLinearになります。拡大処理/縮小処理片方だけか両方か、処理速度、質どちらを優先するのか等から候補を絞りましょう。例えばLanczos4は拡縮どちらもきれいですが処理が重いです。

グレースケール化(Cv2.Cvtcolor)

     Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.AnyColor)
           Using dst As New Mat()
                Cv2.CvtColor(img, dst, ColorConversionCodes.BGR2GRAY)
                PictureBoxIpl1.ImageIpl = dst

           End Using
     End Using

グレースケール化以外にも色々な変換オプションがあります。インテリセンス機能の入力候補を眺めてみると良いでしょう。

2値化(Cv2.Threshold、Cv2.AdaptiveThreshold)

     Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.AnyColor)
           Using dst1, dst2 As New Mat()
                Cv2.CvtColor(img, dst1, ColorConversionCodes.BGR2GRAY)

                Cv2.Threshold(dst1, dst2, 0, 255, ThresholdTypes.Otsu)'通常の2値化
                Cv2.AdaptiveThreshold(dst1, dst2, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 9, 12)'適応的2値化
                
                PictureBoxIpl1.ImageIpl = dst

           End Using
     End Using

2値化は、入力画像がグレースケールでなければなりません。 2値化には通常の2値化と適応的2値化の2種類があります。どのような違いがあるかは、試してみると一目瞭然です。

エッジ処理(Cv2.Canny)

     Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.AnyColor)
           Using dst As New Mat()
                Cv2.Canny(img, dst, 50, 110, 3, False)
                PictureBoxIpl1.ImageIpl = dst

           End Using
     End Using

Cannyのパラメータは、50、110と書いてあるのが閾値、3がapertureSize、FalseがL2Gradientです。後半2つは基本デフォルトのまま、書かなくてもよいかと。閾値は対象の画像によって適切な値は変わります。 こちらはグレースケール画像でなくてもできます。した方がいいのかどうかは分かりません。

画像の保存

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Using img As Mat = Cv2.ImRead("ファイルパス", ImreadModes.Color)
        'いろいろな処理→dstへ格納されているとする

         Cv2.imWrite("./output.bmp",dst)
         dst.SaveImage("./output.bmp") 'どちらでもよい
    End Using

End Sub

imWrite、SaveImageどちらを使っても保存できます。違いは…?私はSaveImageを使っています。

とりあえず基本的な所を。なにができるのかもっと詳しく知りたい方は ドキュメント を見てみましょう。また、Cv2.とかExtensions.とか打って入力候補を眺めても良いかも知れません。

…OpenCVならではの処理を全く書いていないのもあってこの記事の存在価値は0に等しいですが、VB.netの記事はあまりないのでその点で…?

あ、でも今から始めようと思う方はC#を触ったほうが良いですよ。サンプルがたくさんあるし、クロスプラットフォーム開発でもC#が使える(Xamarin)ので、今後もガシガシ使われます。VB.netはコード量は多いけど、感覚的に理解しやすくて私は大好きです。