C#2008で、OpenCVを強引に使う方法

先日までは、科教協とかいう、かなり理科教育にコアな人たちが集団であつまる、よくわからないけれども好きな人にはたまらない集団があつまる発表会があったので行ってきた。

科教協
http://homepage3.nifty.com/kakyoukyou/

教育的に結構面白い内容とか、白金を触媒にしたり自分が物理屋だとしても、科学的な楽しい実験を実際に身近に触れることができるのはよい経験である。
特に物理のナイタが心をくすぶられる。簡単な電子回路だったが、それを教育に応用している熱意がすばらしい。
そういえば、私が新任のときも一所懸命がんばって 光があたったらブザーがなってLEDが光るような回路を作ったのを思い出す。
本当に電子回路は苦手だったので、(トランジスタを使った回路なんてはじめて)トランジスタの使い方から本読んで父上に聞いて勉強しまくったものだ。

またそれ以外にも、極めて嬉しいことがあった旅行だった。

閑話休題
今の研究では、画像処理を行っているが、画像処理を行うための命令を.net frame work上で行っていると、時間がかかりすぎて困っていた。それをインテル製CPUに特化して性能を引き出すOpenCVとかいうライブラリの存在を知った。

OpenCV
http://opencv.jp/

ところがこれは、C++用なのである。これを無理やり強引にC#上で実現する方法について記述する。
これはもうめちゃくちゃ苦労した。最初のシステム導入までは、時間がかかるので絵つきで。
でも、結構手順が複雑なので、最後までいたれる人は最初のような絵はいらないかもしれない・・。

1.OpenCVを普通にインストールする。
インストールは、以下よりできる。英語でわからない人は下の画像の緑のボタンを押下すればよい。
http://sourceforge.net/projects/opencvlibrary/

次は、これの一番したのopencv-winのdownloadを押下

opencv-1.0.exe


ダウンロードしてできたもの(これが激しくセンスが悪いアイコンである。もう少しなんとかならんのか。)
をダブルクリックしてインストールする。
インストールは適当に進めればよいので省略。
ここから面倒なので、省略をしまくる。

2.OpenCVを.net frame workで強引に使うためのOpenCVDotNetを導入する。
いろいろ調べたらgoogle codeで実装している物好きな人いた。

↓ここ
http://code.google.com/p/opencvdotnet/

画面右の緑色のボックスのFeatured Downloads:の中のopencvdotnet-0.7-setup.exeを押下してダウンロード。
ダウンロードしてできたセットアップファイルをインストールすると、
c:\program files\opencvdotnet\ に、フォルダが構築される。
これを使ってプログラミングをするわけではあるが、
C:\Program Files\OpenCVDotNet\src\OpenCVDotNet
にあるプログラムをリビルドしても、ビルドに失敗する。
そこで、このプロジェクトにCVHaar.h を強引に突っ込んで、
リビルドする。
CVHaar.hの中を見ようと思ったらgoogle groups のポリシに同意する必要があり、アカウントをとることが必要になるので、
ここに公開しよう。

/**
 * (C) 2007 Vincenzo D'Alconzo
 * This code is licenced under the GPL.
 */

#pragma once

using namespace System;
using namespace Drawing;
using namespace Imaging;

#include "stdafx.h"

#include "CVRgbPixel.h"
#include "CVUtils.h"
#include "CVHistogram.h"
#include "CVPair.h"
#include "CVArr.h"

#ifdef _EiC
#define WIN32
#endif

namespace OpenCVDotNet
{
	public ref class CVHaar
	{
	protected:
		char* cascade_name_;
		 CvMemStorage* storage;
		 CvHaarClassifierCascade* cascade;
	public:

		CVHaar(String^ cascade_name)
		{
			cascade_name_ = new char[100 + 1];
			CVUtils::StringToCharPointer(cascade_name, cascade_name_, 100);
			cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name_, 0, 0, 0 );
			storage = cvCreateMemStorage(0);
		}
		

		array<Drawing::Rectangle>^ detectPatterns(double scale,CVImage^ cvimg,int x_size,int y_size,
												double scale_factor,double min_neighbors,int pruning_mode)
		{
			IplImage* img = cvimg->Internal;
			IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
			IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),
															cvRound (img->height/scale)),8, 1 );
			
            			
			
			cvCvtColor( img, gray, CV_BGR2GRAY );
			cvResize( gray, small_img, CV_INTER_LINEAR );
			cvEqualizeHist( small_img, small_img );
			cvClearMemStorage( storage );
			CvSeq* faces = 0;
			CvRect* r = 0;
			array<Drawing::Rectangle> ^rects;
			if( cascade )
			{
				CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
					scale_factor, min_neighbors, pruning_mode/*CV_HAAR_DO_CANNY_PRUNING*/,
					cvSize(x_size, y_size) );
				rects = gcnew array<Drawing::Rectangle>(faces->total);

				for(int i = 0; i < (faces ? faces->total : 0); i++ )
				{
					r = (CvRect*)cvGetSeqElem( faces, i );

					
					rects[i].X = r->x*scale;
					rects[i].Y = r->y*scale;
					rects[i].Width =  r->width*scale;
					rects[i].Height = r->height*scale;

					//CvPoint center;
					//int radius;
					//center.x = cvRound((r->x + r->width*0.5)*scale);
					//center.y = cvRound((r->y + r->height*0.5)*scale);
					//radius = cvRound((r->width + r->height)*0.25*scale);
					//cvCircle( img, center, radius, colors[i%8], 3, 8, 0 );
				}
				
			}

			cvReleaseImage( &gray );
			cvReleaseImage( &small_img );
			return rects;
		}
	};
};

そうしてリビルドすると、
OpenCVDotNet.dll
が無事に生成されるので、
これをC#のプロジェクトに参照してあげると、C#上で、OpenCVを扱うことができる。
これをすることで、画像処理のスピードが100倍以上高速に実行することができる。

簡潔な記述は、
http://ymlabo.ddo.jp/~ymlab/wiki/index.php?C%20Sharp%20Tips#pa3175a2
ただし、自宅サーバTTLが600なDDNSでやっているため、アクセスできないことがある。
以上。