メモりメモる

ハトいエンジニアのアメリカ生活と技術のメモ。

iOSアプリ開発ではじめるOpenCV再入門

iPhoneアプリでOpenCVを動かそう!としたら、色々と苦戦したり茨の道だったので、そのレポートを書きます。
※Xcode4.3,SDK5.1で開発しました。
f:id:hatyone:20120707161640j:plain

  • 参考にしたサイト

「OpenCV iPhone」で検索すると、真っ先にヒットするページです。
yoshimasa niwa - iPhoneでOpenCVを使う方法
こちらを参考にさせていただきました。
上記サイトで配布されているビルド済みライブラリをインポートしてそのまま使おうとすると、最新SDKとバージョンが違うので動きませんでした。


  • ライブラリをビルドする準備

1.サンプルコードをダウンロード
上記のページのコメント欄に、stephanepechard/iphone_opencv_test · GitHubというリポジトリがあるので、こちらを使ってみます。

% git clone git://github.com/stephanepechard/iphone_opencv_test.git
% cd iphone_opencv_test
% wget http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.2/OpenCV-2.2.0.tar.bz2/download
% tar xjvf download

2. cmakeをインストール
cmakeでビルドをするので、ない場合はインストールしましょう。

% brew install cmake

3.OpenCVをiOS SDKでビルド出来るように、パッチを当てます

% cd OpenCV-2.2.0
% patch -p1 < ../OpenCV-2.2.0.patch

4.opencv_cmake.shを書き換える

if [ -z "$SDK_VERSION" ]; then
 SDK_VERSION="5.1"  //SDKのバージョンを5.1にする
fi
//Xcode4.3からSDKの場所が変わってるので、それに合わせる
DEVELOPER_ROOT="/Applications/Xcode.app/Contents/Developer/Platforms/${TARGET_SDK_NAME}.platform/Developer"
SDK_ROOT="${DEVELOPER_ROOT}/SDKs/${TARGET_SDK_NAME}${SDK_VERSION}.sdk"

 
  

  • ライブラリをビルドしてみる

iOSのシュミレーターと実機は、CPUが異なるので、2つ分ライブラリを用意します。
1.シュミレーターのライブラリ

% cd .. 
% mkdir build_simulator
% cd build_simulator
% ../opencv_cmake.sh Simulator ../OpenCV-2.2.0
% make -j 4
% make install

2.実機のライブラリ

% cd .. 
% mkdir build_device
% cd build_device
% ../opencv_cmake.sh Device ../OpenCV-2.2.0
% make -j 4
% make install

 
  

  • Xcodeのライブラリのパスを設定

Library Search Pathsで、シミュレータと実機向けのパスを指定します。
f:id:hatyone:20120707175339p:plain
 
  

  • freamworkの追加

Accelerate.frameworkというフレームワークがOpenCVでは必要となるので追加します。
f:id:hatyone:20120707175943p:plain


  • 早速OpenCVを使ってみる

yoshimasa niwa - iPhoneでOpenCVを使う方法を参考にして、UIImageとIplImageの相互変換することが出来ます。


UIImage -> lplimage

// NOTE you SHOULD cvReleaseImage() for the return value when end of the code.
- (IplImage *)CreateIplImageFromUIImage:(UIImage *)image {
	CGImageRef imageRef = image.CGImage;

	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	IplImage *iplimage = cvCreateImage(cvSize(image.size.width, image.size.height), IPL_DEPTH_8U, 4);
	CGContextRef contextRef = CGBitmapContextCreate(iplimage->imageData, iplimage->width, iplimage->height,
													iplimage->depth, iplimage->widthStep,
													colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault);
	CGContextDrawImage(contextRef, CGRectMake(0, 0, image.size.width, image.size.height), imageRef);
	CGContextRelease(contextRef);
	CGColorSpaceRelease(colorSpace);

	IplImage *ret = cvCreateImage(cvGetSize(iplimage), IPL_DEPTH_8U, 3);
	cvCvtColor(iplimage, ret, CV_RGBA2BGR);
	cvReleaseImage(&iplimage);

	return ret;
}


lplimage -> UIImage

// NOTE You should convert color mode as RGB before passing to this function
- (UIImage *)UIImageFromIplImage:(IplImage *)image {
	NSLog(@"IplImage (%d, %d) %d bits by %d channels, %d bytes/row %s", image->width, image->height, image->depth, image->nChannels, image->widthStep, image->channelSeq);

	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	NSData *data = [NSData dataWithBytes:image->imageData length:image->imageSize];
	CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
	CGImageRef imageRef = CGImageCreate(image->width, image->height,
										image->depth, image->depth * image->nChannels, image->widthStep,
										colorSpace, kCGImageAlphaNone|kCGBitmapByteOrderDefault,
										provider, NULL, false, kCGRenderingIntentDefault);
	UIImage *ret = [UIImage imageWithCGImage:imageRef];
	CGImageRelease(imageRef);
	CGDataProviderRelease(provider);
	CGColorSpaceRelease(colorSpace);
	return ret;
}


注意点として、 IplImage->UIImage と変換する際に、cvCvtColor(src_image, dst_image, CV_BGR2RGB);のようにBGRからRGBに変換しなければ、変な色として出力されてしまいます。
気をつけましょう。


こんな流れで、iOS上でOpenCVを扱うことが出来ます。

//画像を読み込む
UIImage *src_image=[UIImage imageNamed:@"sample.png"];
//OpenCVで使われるIplImage形式に変換
IplImage *cv_image = [self CreateIplImageFromUIImage:src_image];

//-----ココらへんでOpenCVな処理を書く

//BGRになっているのでRGBに変換
cvCvtColor(cv_image, cv_image, CV_BGR2RGB);

//IplImageをUIImageへ変換
UIImage *dst_photo = [self UIImageFromIplImage:dst_image];


  • ハマったポイントと対処方法

1.配布されていいるライブラリそのまま使っても動かない…
SDKのバージョンが違うので、大人しくビルドしましょう

2.画像が表示されない…
→cvCreateImage(cvGetSize(src_image),IPL_DEPTH_8U,3);みたいな部分で、画像のサイズやチャンネル数が一致してるか確認しましょう

3.色が、なんか…すごく変…
→RGBとかBGRとかそこら辺を疑いましょう


[追記]
dandelion (dandelion1124) sur Twitterさんからリプライを頂きました。
OpenCV 2.4.2からはiOS用frameworkが公式に配布されているそうです。
frameworkとして生成できるので、導入がとても簡単そうです。
Installation in iOS — OpenCV v2.4.9 documentation