恥ずかしげもなく技術ブログ

プログラミング等について書いていきます.

iOSでOpenCVついでにGrabCut

iOSでgrabCutを使う機会があったのでやってみました.

自分はgrabCut自体は知っているのですが実際にOpenCVから使ったことがなかったためiOSOpenCVを使うというのとgrabCutを利用するという2つのチャレンジをしました.

 

(1) まずOpenCVの導入・動作

[1]まずネットからOpenCVをDL.2014/09/05の段階で最新はOpenCV3.0ですがα版なので2.4.9をDLします.

DOWNLOADS | OpenCV

の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;

}

/*****/