読者です 読者をやめる 読者になる 読者になる

C#でOpenCVを使う(C++/CLIによる方法)

OpenCVラッパクラス

C#でOpenCVを手軽に使うには

OpenCvSharpをつかう その17(NuGetで導入) - schima.hatenablog.com
C#でOpenCVを動かす~NuGetでOpenCV.Netをインストール - whoopsidaisies's diary

のページのように,NuGetからC#ラッパをインストールして使う方法があるが,必要な機能がラッピングされていないことがある.

このページでは,C++/CLIでOpenCVの必要な機能だけ持つラッパクラスを自分で作り,C#から呼び出す方法を紹介する.

C++/CLI

通常のC++のライブラリをC#から呼び出そうとするとDllImport属性で宣言が必要だったりして面倒であるが,C++/CLIで作ったDLLであれば参照に追加するだけで使用できる.

手順

手順は以下の通りである.

C#プロジェクト作成

実行されるC#のプロジェクト

C++/CLIのDLL用プロジェクト作成

OpenCVをラップするクラス用のプロジェクト

プロジェクトの参照の設定

作成したクラスをC#から読み込むための設定

OpenCVのインストール

OpenCVのインストール

C++/CLIでラッパクラスの作成

OpenCVによる処理部分の実装

C#のプロジェクトの出力パスの変更

OpenCVのDLLの場所とかの関係上の設定

C#から呼び出す

C#からの呼び出し部分とGUIの実装


以下に各手順の詳細を記す.

C#プロジェクト作成

Visual Studioで新しいプロジェクトを作成する.
f:id:whoopsidaisies:20140112101313p:plain

C++/CLIのDLL用プロジェクト作成

ソリューションを右クリックして,「追加」の「新しいプロジェクト(N)...」でC++/CLIのDLL作成用のプロジェクトを作成する.「Visual C++」の「CLR」の「クラス ライブラリ」を選択.
f:id:whoopsidaisies:20140112101334p:plain

プロジェクトの参照の設定

C++/CLIで作成したDLLをC#から呼び出すための参照設定を行う.C#のプロジェクト内の「参照設定」を右クリックし「参照の追加(R)...」を選択する.開いたダイアログで「ソリューション」の「プロジェクト」を選択し,C++/CLIのプロジェクトの名前のところにチェックを入れる.
f:id:whoopsidaisies:20140112101620p:plain
f:id:whoopsidaisies:20140112102324p:plain

OpenCVのインストール

C++/CLIのプロジェクトを右クリックし「NuGet パッケージの管理」を選択.ダイアログで「オンライン」を選択し,検索窓で「OpenCV」を検索,インストールする.
f:id:whoopsidaisies:20140112101806p:plain

C#のプロジェクトの出力パスの変更

NuGetでインストールしたOpenCVのDLLが,C#プロジェクトで作成した実行ファイルから参照できる位置に配置されないため,実行ファイルの出力パスを変えてやる.C#のプロジェクトを右クリックし「プロパティ(R)」を選択.「ビルド」の「出力パス」を「..\Debug\」に変える(Releaseモードなら..\Release\).
f:id:whoopsidaisies:20140112110351p:plain
この手順を忘れると,実行時に以下のようなエラーメッセージが表示されてOpenCVの呼び出しに失敗する.
f:id:whoopsidaisies:20140112110400p:plain

C++/CLIでラッパクラスの作成

C++/CLIでOpenCVの処理のコードを書く.C++/CLIのプロジェクトを作成したときに色々とファイルが生成されているので,そのうちの「OpenCvClrLibrary.h」(プロジェクト名.h)を以下のようにする.画像をファイルから読み込んで,BRISK特徴点を抽出して表示するサンプルである.

// OpenCvClrLibrary.h

#pragma once
#include <opencv2/opencv.hpp>

using namespace System;

namespace OpenCvClrLibrary {

	public ref class TestClass
	{
	public:
		static void TestMethod()
		{
			auto image = cv::imread("Penguins.jpg");

			auto brisk = cv::BRISK();
			std::vector<cv::KeyPoint> keyPoint;
			brisk.detect(image, keyPoint);
			cv::drawKeypoints(image, keyPoint, image);

			cv::imshow("image", image);
			while (cv::waitKey(1) == -1);
			cv::destroyAllWindows();
		}
	};
}

「ref class」はC++/CLI用のクラス.詳細は省略するが,こういう書き方をすることでC#でそのまま使えるクラスを作れる.
「auto」はc++11から追加された機能で,変数の初期値から型推論を行ってくれる.Visual Studio 2012以降では使えるみたい.横に長くなりがちなOpenCV(に限らないけど)のコードではこれを使えるのは嬉しい.

C#から呼び出す

C#から上記の特徴点抽出処理を呼び出すコードを以下のように書く.

using System;
using System.Windows.Forms;

namespace OpenCvFromCSharp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenCvClrLibrary.TestClass.TestMethod();
        }
    }
}

Buttonコントロールを配置して,クリックすると特徴点が書き込まれた画像が以下のように表示される.

f:id:whoopsidaisies:20140112104341p:plain