iOS で opencv を使う。


## 評価環境

* xcode5
* opencv 2.4.9


## opencv のダウンロード
[http://opencv.org/downloads.html](http://opencv.org/downloads.html)
以下から framework をダウンロードします。
![スクリーンショット 2014-06-21 20.47.43.png](https://qiita-image-store.s3.amazonaws.com/0/30578/511b273b-30eb-ce1f-1eb2-e87b1a773cd6.png "スクリーンショット 2014-06-21 20.47.43.png")

framework を利用すると非常に簡単に組み込めます。
その一方、framework作成時のコンパイラ設定とプロジェクトのコンパイラ設定が異なるとビルドできないこともあります。
自分でビルドすれば、コンパイラの設定違いに悩まされることはないです。
少なくともこの記事の記載時点では、特にプロジェクトのデフォルトの設定から変える必要はありません。


## xcode でプロジェクトから参照する
プロジェクトでフレームワークを追加します。
先ほどダウンロードしたフレームワークを指定します。

![スクリーンショット 2014-06-21 18.00.24.png](https://qiita-image-store.s3.amazonaws.com/0/30578/1d7b6400-6690-3344-8d04-4bb778d087dc.png "スクリーンショット 2014-06-21 18.00.24.png")

## ソースを .mm にする
opencv の c++ ライブラリを使うので、ソースを .mm にします。
これで objective-c と c++ の混在ができます。
![スクリーンショット 2014-06-21 20.58.21.png](https://qiita-image-store.s3.amazonaws.com/0/30578/8b1167ea-3d43-923c-2a57-2843fc11e4af.png "スクリーンショット 2014-06-21 20.58.21.png")

## ヘッダをインポートします

```objective-c
// .mm ファイル

// opencv の import
#import <opencv2/opencv.hpp>
#import <opencv2/highgui/ios.h>

```
## opencv を使う
iOS では一般的に UIImage 型を利用します。
一方 opencv では cv::Mat 型を利用します。

そのため、iOS 上での一般的な処理の流れは以下のようになります。

1. UIImage を cv::Mat に変換する。
1. opencv API を利用します。
1. cv::Mat を UIImage に変換して、表示などに利用。
  


### UIImage を cv::Mat にする
UIImageToMat を用います。
変換のために以下のような変換メソッドを用意します。

```objective-c
- (cv::Mat)matWithImage:(UIImage*)image
{
    // 画像の回転を補正する（内蔵カメラで撮影した画像などでおかしな方向にならないようにする）
    UIImage* correctImage = image;
    UIGraphicsBeginImageContext(correctImage.size);
    [correctImage drawInRect:CGRectMake(0, 0, correctImage.size.width, correctImage.size.height)];
    correctImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    // UIImage -> cv::Mat
    cv::Mat mat;
    
    UIImageToMat(correctImage, mat);
    return mat;
}

```

### cv::Mat を UIImage にする
MatToUIImage を用います。

### サンプルコード

```objective-c
//
//  ViewController.mm
//  opencvSample1
//
//

#import "ViewController.h"

#import <opencv2/opencv.hpp>
#import <opencv2/highgui/ios.h>

@interface ViewController () {
    UIImage*    _origImage;
}

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
   
    // ImageView の Outlet として imageView を用意した。
    // imageView には予め画像を設定してあるので、ここで元の画像をとっておく。
    _origImage = self.imageView.image;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (cv::Mat)matWithImage:(UIImage*)image
{
    // 画像の回転を補正する（内蔵カメラで撮影した画像などでおかしな方向にならないようにする）
    UIImage* correctImage = image;
    UIGraphicsBeginImageContext(correctImage.size);
    [correctImage drawInRect:CGRectMake(0, 0, correctImage.size.width, correctImage.size.height)];
    correctImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    // UIImage -> cv::Mat
    cv::Mat mat;
    
    UIImageToMat(correctImage, mat);
    return mat;
}
- (IBAction)onGray:(id)sender {
    cv::Mat     mat = [self matWithImage:_origImage];
    
	// グレイスケール化
    cv::cvtColor(mat, mat, CV_BGR2GRAY);
	// 変換結果を画面に表示
    self.imageView.image = MatToUIImage(mat);
}

- (IBAction)onNot:(id)sender {
    cv::Mat     mat = [self matWithImage:_origImage];
    // ネガポジ反転
    mat = ~mat;
    
    self.imageView.image = MatToUIImage(mat);
}

- (IBAction)onOtsu:(id)sender {
    cv::Mat     mat = [self matWithImage:_origImage];
    
	// グレイスケール化してから大津法で二値化
    cv::cvtColor(mat, mat, CV_BGR2GRAY);
    cv::threshold(mat, mat, 0, 255, cv::THRESH_BINARY|cv::THRESH_OTSU);
    self.imageView.image = MatToUIImage(mat);
}

- (IBAction)onAdaptive:(id)sender {
    cv::Mat     mat = [self matWithImage:_origImage];
    
	// グレイスケール化してから適応的二値化
    cv::cvtColor(mat, mat, CV_BGR2GRAY);
    cv::adaptiveThreshold(mat, mat, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY, 7, 8);
    self.imageView.image = MatToUIImage(mat);
}

```

### サンプルコードによる出力例

元画像
![スクリーンショット 2014-06-21 21.22.13.png](https://qiita-image-store.s3.amazonaws.com/0/30578/9ae94bbe-7201-66a1-4336-04b8d8c9918b.png "スクリーンショット 2014-06-21 21.22.13.png")


グレイスケール画像
![スクリーンショット 2014-06-21 21.20.55.png](https://qiita-image-store.s3.amazonaws.com/0/30578/f6965d1e-1494-6a70-cd8e-48af8ef2c408.png "スクリーンショット 2014-06-21 21.20.55.png")

ネガポジ反転
![スクリーンショット 2014-06-21 21.21.40.png](https://qiita-image-store.s3.amazonaws.com/0/30578/96084b9b-0dab-8781-c542-f46b18912972.png "スクリーンショット 2014-06-21 21.21.40.png")

大津法による二値化
![スクリーンショット 2014-06-21 21.22.40.png](https://qiita-image-store.s3.amazonaws.com/0/30578/9d5bbcc6-bad8-63d1-6b3b-2e80b76a904a.png "スクリーンショット 2014-06-21 21.22.40.png")

適応的二値化
![スクリーンショット 2014-06-21 21.23.13.png](https://qiita-image-store.s3.amazonaws.com/0/30578/d26cf060-2a58-e356-d3f9-71dc99a509bc.png "スクリーンショット 2014-06-21 21.23.13.png")




## 実機での評価
実機でうまく動かせない場合は、Architecture を以下のように変更します。
![スクリーンショット 2014-06-21 18.01.39.png](https://qiita-image-store.s3.amazonaws.com/0/30578/6cc6aec9-34e9-cfa8-d074-39f85f46b5ac.png "スクリーンショット 2014-06-21 18.01.39.png")