OpenCvSharpを使う その1 (準備)

※NuGetパッケージを公開しました。この記事より簡単に導入できますので、今後はNuGetをお勧めします。説明は以下から。
http://schima.hatenablog.com/entry/2013/12/15/110513



開発がひとまず一段落し、もう今後大きく仕様が変わることはなさそうなので、これから何回かかけてOpenCvSharpの導入の仕方や、使い方、サンプルなどを紹介していこうと思います。
実のところ、開発しておきながら自分ではあまり使っていないという事情もあるので、使い心地を確かめるという意味もあります。

OpenCvSharpをつかう 記事一覧

OpenCvSharpについて

OpenCvSharpは、画像処理などを行うライブラリであるOpenCVを、.NET Frameworkの言語(主にC#を想定)から利用するためのラッパーです。

https://github.com/shimat/opencvsharp

他に同様のラッパーが無いわけではありません(こちら)。それらと比べたときのOpenCvSharpの特徴は以下の通り。

利点

CでOpenCVを使うときと極力似た記述ができるようにしている
Emgu CVは優れたラッパーですが、記述が元とかなりかけ離れているために、なかなか使い方が分からなかったりする場合があります。OpenCvSharpは、C/C++で書かれたOpenCVのコードをC#っぽく書き直すだけで動く、ということを重視しています。
ラップしている関数が多い
結局これに尽きるかと思います。使い心地は慣れや我慢でどうにでもなりますが、使いたい関数がまだラップされてないとなるとどうしようもありません。OpenCvSharpはリファレンスマニュアルに載っている関数はほぼ全て網羅しています。全ラッパー中で最も網羅率は高いはず。
XMLドキュメントコメントが日英両対応
他のラッパーではそもそも無いか、有っても当然英語のみなので、これは日本人にはありがたいことじゃないかと思っています。かなり血のにじむような苦労のもと実現しています。訳文は日本語版リファレンスマニュアルのものを拝借しています。
Monoでも動作する
つまりLinuxMac OS Xなどでも動く、はず。

欠点

逆に欠点を挙げてみると、

システム要件が高め
Windows専用で、.NET Framework3.5を必要としています(.NET Framework2.0でも動くようになりました)。マルチプラットフォーム化の野望はあるのですが、余力がかなり不足気味。
Monoで動作するようになりました!
抽象度がそんなに高くない
そこそこC#っぽく書けるようにはしていますが、Emgu CVほどまるっきり引数も何もかもC#らしくしたりといったことはしてません。
作者の英語力が低い
ので海外の方との色々なやり取りにはかなり難があります。中学英語を頼みに今のところはなんとかやっていますが。
作者の気まぐれでころころ仕様が変わる
さすがにそろそろ安定期に入るはず・・・

OpenCvSharpを使う

それでは、適当なコードを動かすまでの準備の過程を書いていきます。

ダウンロード

以下GitHubのページから、緑色のボタンを押してダウンロードします。
https://github.com/shimat/opencvsharp/releases


OpenCvSharpの2.1とか1.1preといったバージョンは、OpenCVと対応しています。例えばOpenCV 2.1をインストールしているのであれば、OpenCvSharpも2.1のものをダウンロードします。


x86(32ビット)版x64(64ビット)版 があります。普通はx86の方を選択しておけば大丈夫でしょう。

注意として、x64版の「64ビット」というのは、正確には64ビットOS向けという意味ではなく、64ビットのOpenCV向けという意味です。64ビットOSを利用している人でも、インストーラを使い32ビット版のOpenCVを入れたという場合は、OpenCvSharpはx86版を利用してください。x64版を使うためには、CMakeを使いOpenCVも64ビット用にコンパイルしなければいけません。

Visual C++ 再頒布可能パッケージ のインストール

ネイティブの関数を呼び出すため必要です。以下の中から自分のプラットフォームに合うものをインストールしましょう。念のため、x86 または x64 のもの3つを全てインストールしておくと安心です。

x86
Visual C++ 2010 Redistributable Package (x86)
Visual C++ 2008 SP1 Redistributable Package (x86)
Visual C++ 2005 SP1 Redistributable Package (x86)

x64
Visual C++ 2010 Redistributable Package (x64)
Visual C++ 2008 SP1 Redistributable Package (x64)
Visual C++ 2005 SP1 Redistributable Package (x64)

プロジェクトの作成

Visual Studio 2005 / 2008 / 2010 を起動します。Expressでも充分です。

新しいプロジェクトを作成します。「コンソール アプリケーション」か若しくは「Windows フォーム アプリケーション」を選択します。

バイナリのコピー

ダウンロードしたOpenCvSharpのdllやxmlファイルなど一式をプロジェクトに全部突っ込みます。ファイルを全部選択し、ソリューションエクスプローラにドラッグドロップします。

今のところ、これらを全部使うわけではありませんが、説明の簡単のため。

OpenCvSharpExtern.dllのコピー設定

MachineLearning(機械学習)・Blob(ラベリング)・CPlusPlus(OpenCVC++ Interfaceラッパー)を利用する場合のみ、以下の設定が必要です。使わない場合はこの節は読み飛ばしてください。

MachineLearningやBlobを利用するためには、C++C#の橋渡しをする「OpenCvSharpExtern.dll」が必要です。このDLLが実行ファイルと同じディレクトリに無ければなりません。そこで、プロパティを編集し、出力ディレクトリに「新しい場合はコピーする」設定にします。


参照設定

ソリューションエクスプローラにある「参照設定」を右クリックして「参照の追加」を選択します。そして、OpenCvSharpの各DLLを参照に追加します。


OpenCvSharp.dllは必須なので必ず追加します。他の4つは拡張機能です。多くの人にとってはあまり出番は無いかもしれません。


なお、OpenCvSharpExtern.dll に対し参照設定する必要はありません(できません)。MachineLearningなどを使う場合のみ、前節の説明に従って設定し置いておくだけです。OpenCvSharpの内部で利用される低レベルなラッパー関数が定義されており、普通の利用者は直接はアクセスしません。

実行

Program.cs を以下のように書き換えて、実行します。

using System;
using System.Collections.Generic;
using System.Text;
using OpenCvSharp;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IplImage img = Cv.CreateImage(new CvSize(128, 128), BitDepth.U8, 1);

            for (int y = 0; y < img.Height; y++)
            {
                for (int x = 0; x < img.Width; x++)
                {
                    Cv.Set2D(img, y, x, x + y);
                }   
            }

            Cv.NamedWindow("window");
            Cv.ShowImage("window", img);
            Cv.WaitKey();
            Cv.DestroyWindow("window");
            
            Cv.ReleaseImage(img);
        }
    }
}

このようなウィンドウが表示されたら成功です。

ここではわざとC/C++での記述に近いコードにしてみました。もう少しC#っぽく楽に書く方法も用意していますがそれはまた今度。

うまくいかない場合

OpenCVのDLLもコピー

もしうまくいかない場合は、OpenCVのcv110.dllやcxcore110.dllなどのバイナリファイルも全部プロジェクトに入れてみましょう。これらは、OpenCvSharpExtern.dllと同様に、プロパティで「新しい場合はコピーする」設定にしておきます。

(.NETのバイナリではないので、参照設定をする必要はありません。実行ファイルと同じ場所に置くことが大事です。)

Visual C++のランタイムをインストール

しかし、OpenCVのDLLを置いたにもかかわらず、以下のようなエラーが出る場合があります。

例外の種類を字面通り受け取ると、今置いたはずのcxcore110.dllが無いということになりますが、そうではなく、cxcore110.dllが依存しているC++のランタイムライブラリが無いという可能性が高いです。公式のリリースされているdllの場合はmsvcr80.dllあたりに依存していますので、以下のページから「Microsoft Visual C++ 2005 SP1 再頒布可能パッケージ」をインストールしましょう。

http://www.microsoft.com/downloads/details.aspx?FamilyID=200b2fd9-ae1a-4a14-984d-389c36f85647&displaylang=ja

2005でだめなら2008も。
http://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=a5c84275-3b97-4ab7-a40d-3802b2af5fc2

(最近のバージョンではDllNotFoundExceptionではなくTypeLoadExceptionになるかもしれません。原因は同じです。)

BadImageFormatException

おそらく原因は、導入したOpenCvSharpとOpenCVの対象プラットフォームが違うということです。OpenCVは32ビット向けなのに、OpenCvSharpをx64で利用している、といった場合です。

32ビットOSの人は、x86版のOpenCvSharpを使っているのかどうか確認してください。

64ビットOSの人は、まず、利用しているOpenCVが32ビットなのか64ビットなのか確認してください。上の方でも書きましたが、OpenCvSharpのx64版というのは、正確には64ビットOS向けという意味ではなく、64ビットのOpenCV向けという意味です。64ビットOSを利用している人でも、インストーラを使い32ビット版のOpenCVを入れたといった場合は、OpenCvSharpはx86版を利用してください。x64版を使うためには、CMakeを使いOpenCVも64ビット用にコンパイルしなければいけません。

64ビットOSの人がx86版のOpenCvSharpを使う場合は、C#側でのビルドのプラットフォーム設定を「Any CPU」から「x86」に変更します。(Any CPUのままでは実行時にx64で動作してしまい、32ビットのライブラリと整合性が取れなくなりBadImageFormatExceptionが発生します。)

無ければ構成マネージャで新規作成して出します。この際に、「ビルド」のところのチェックが入らないことがありますので要チェック。


このページの下の方にもプラットフォーム設定の手順が書いてあります。
http://www.broculos.net/tutorials/badimageformatexception_was_unhandled/20080307/en