iOSでOpenCVついでにGrabCut
iOSでgrabCutを使う機会があったのでやってみました.
自分はgrabCut自体は知っているのですが実際にOpenCVから使ったことがなかったためiOSでOpenCVを使うというのとgrabCutを利用するという2つのチャレンジをしました.
(1) まずOpenCVの導入・動作
[1]まずネットからOpenCVをDL.2014/09/05の段階で最新はOpenCV3.0ですがα版なので2.4.9をDLします.
の2.4.9 for iOSをダウンロードしてください.
[2]次に適当にxcodeでプロジェクトを作り,左の一覧から自分のプロジェクト名をクリックした後,中央の画面の一番下にあるLinked Frameworks and Librariesで+を選択し先ほどDLしたOpenCVのフレームワークを選択.
[3]同じく左の一覧からSupporting Files/(自分のプロジェクト名)-Prefix.pchを選択し,
#ifdef __cplusplus
#import <opencv2/opencv.hpp>
#endif
を最後に追加.
[4] opencvを使いたいファイルの拡張子を.mから.mmに変える.ViewController.mmとか.これでOpenCVが使えます.
(2) grabCutの利用
ネットに落ちているコードを継ぎ接ぎしたり,
OpenCVのリファレンスとサンプルコード:
opencv/grabcut.cpp at master · Itseez/opencv · GitHub
を参考にして作りました.
----
// UIImageとして読み込み,その後cv::Matに変換
cv::Mat srcMat = [self cvMatFromUIImage:[UIImage imageNamed:@"0919.jpg"]];
cv::Mat dst;
//今回はひとまず矩形領域だけで全景領域切り出す.
//なのでこのマスクは初期化の必要なし
cv::Mat mask;
//これは反復演算のときに使われるらしい
//同じ画像に対して同じ行列を使うということだけを意識すれば初期化不要
cv::Mat output1,output2;
//矩形領域 これより外側は背景として扱われる
//ここではパンイベントを取って矩形領域を指定するメソッドを別に書き,
//それをもとに矩形領域を設定
cv::Rect rect(cv::Point(self.leftUp.x,self.leftUp.y), cv::Point(self.rightDown.x,self.rightDown.y));
//ネットに落ちてるのはRGBA画像なのでRGBに変換
cv::cvtColor(srcMat , srcMat , CV_RGBA2RGB);
dst = srcMat.clone();
rect.x = (int)fmax(0, rect.x);
rect.y = (int)fmax(0, rect.y);
rect.width = (int)fmin(rect.width, self.imgView.image.size.width);
rect.height = (int)fmin(rect.height, self.imgView.image.size.height);
cv::grabCut(srcMat, mask, rect, output1, output2, 10, cv::GC_INIT_WITH_RECT);
mask &= 1;
for (int w=0;w<mask.cols;w++){
for (int h=0;h<mask.rows;h++){
if (mask.at<uchar>(cv::Point(w,h))==0){
dst.at<cv::Vec3b>(cv::Point(w,h))=0;
}
}
}
self.imgView.image = [self UIImageFromCVMat:dst];
----
変換コードはネットに落ちているものをそのまま使わせて頂きました.
/*****/
- (cv::Mat)cvMatFromUIImage:(UIImage *)image
{
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
CGFloat cols = image.size.width;
CGFloat rows = image.size.height;
cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels
//cvMat.convertTo(cvMat, CV_8UC3);
CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to data
cols, // Width of bitmap
rows, // Height of bitmap
8, // Bits per component
cvMat.step[0], // Bytes per row
colorSpace, // Colorspace
kCGImageAlphaNoneSkipLast |
kCGBitmapByteOrderDefault); // Bitmap info flags
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image.CGImage);
CGContextRelease(contextRef);
//CGColorSpaceRelease(colorSpace);
return cvMat;
}
- (UIImage *)UIImageFromCVMat:(cv::Mat)cvMat
{
NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
CGColorSpaceRef colorSpace;
if (cvMat.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridgeCFDataRef)data);
// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(cvMat.cols, //width
cvMat.rows, //height
8, //bits per component
8 * cvMat.elemSize(), //bits per pixel
cvMat.step[0], //bytesPerRow
colorSpace, //colorspace
kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info
provider, //CGDataProviderRef
NULL, //decode
false, //should interpolate
kCGRenderingIntentDefault //intent
);
// Getting UIImage from CGImage
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
//CGColorSpaceRelease(colorSpace);
return finalImage;
}
/*****/