iOS(swift)でOpenCVを使うシンプルなサンプル


iOS(swift)でOpenCVを使うシンプルなサンプル

ふとiOSでOpenCVを使いたくなったのですが、iOSのプログラミング経験がなかったので、0から調べつつサンプルを作ってみました。
他にも同様のことをやっている記事がいくつかありましたが、情報を整理する意味でも自分なりにまとめることにしました。
swiftからOpenCVを使って入力画像をグレースケール変換するだけのシンプルなサンプルです。(Xcodeの使い方が多め)

CocoaPodsのセットアップ

CocoaPodsはiOSのライブラリ管理ツールです。OpenCVはCocoaPods経由でインストールします。
CocoaPodsのインストールにはRubyGemsを用います。

以下のコマンドを実行してセットアップします。

$ sudo gem install cocoapods
$ pod setup

プロジェクトの作成

次にXcodeを立ち上げます。バージョンはVersion 9.2を使いました。
Xcodeを起動すると以下のウインドウが表示されるので、Create a new Xcode projectをクリックします。

Single View Applicationは何もないまっさらなアプリで一番シンプルなので、それを選択し次へをクリック。

続いて、プロジェクトの詳細設定です。
今回はシミュレータでのみの実行なので、Teamは必要ありません。(実機で動作させたい場合に必要になります)
ProductNameはOpenCVSwiftSample、Languageはswiftとしました。その他は初期設定のままです。適当なディレクトリを指定して作成をしましょう。

CocoaPodsを用いてOpenCVをインストール

ここで一度Xcodeを閉じます。
ターミナルから先ほどXcodeプロジェクトを作成したディレクトリ(.xcodeprojがあるディレクトリ)に移動して以下を実行します。

$ pod init

するとPodfileというファイルが作成されるので、これを以下のように編集します。
(OpenCV3系だとO Linker Errorなどの不具合があるため、今回は2系を入れます)

target 'OpenCVSwiftSample' do
  use_frameworks!

  # Pods for opencvSwiftTest
  platform :ios, "9.0"
  pod 'OpenCV', '2.4.9'
end

下記のコマンドを実行すればOpenCVのインストールが始まります。

$ pod install

Objective-CからOpenCVを呼び出す

Swiftではc言語で記述されたOpenCVを実行することができないので、Objective-Cの中にOpenCVの処理を記述し、それをSwiftから呼び出します。

まずFinderからOpenCVSwiftSample.xcworkspace を開き、Xcodeを起動します。(.xcodeprojでないので注意)

OpenCVSwiftSampleのディレクトリを右クリックしてNew FileからCocoa Touch Classを選択し、nextと進みます。

ClassはOpenCVSample、Subclass of はNSObject、Languageは Objective-C を選択してください。

nextをクリックしcreateを押すと、以下のようなダイアログが立ち上がります。

SwiftからObjective-Cを実行するにはbridging headerなるものが必要で、それをXcodeが自動で生成してくれます。
ファイル名は{project-name}-Bridging-Header.hといったものになります。
詳しくはこちらに記載されています。
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

※ここでCocoa Touch ClassではなくObjective-Cを選んでしまうとBridge-headerは自動で生成されないようです。

また今回はOpenCVのC++ライブラリを用いるため、Objective-C++ というものを用います。
こちらは作成されたOpenCVSample.mのファイル拡張子を.mmに変更するだけでObjective-C++として使用できます。

bridging headerファイルで先ほど作成したOpenCVSample.hファイルをインポートします。

OpenCVSwiftSample-Bridging-Header.h
#import "OpenCVSample.h"

次にヘッダーファイルにメソッドを宣言します。

OpenCVSample.h
#import <UIKit/UIKit.h>

@interface OpenCVSample : NSObject
+(UIImage *)GrayScale:(UIImage *)image;
@end

続いて実装ファイルです。
処理としてはUIImagをmatrix(cv::Mat)に変換して画像処理を行なった後にUIImageに再変換しています。

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

#import "OpenCVSample.h"

@implementation OpenCVSample

+(UIImage *)GrayScale:(UIImage *)image{
    // convert image to mat
    cv::Mat mat;
    UIImageToMat(image, mat);

    // convert mat to gray scale
    cv::Mat gray;
    cv::cvtColor(mat, gray, CV_BGR2GRAY);

    // convert to image
    UIImage * grayImg = MatToUIImage(gray);

    return grayImg;
}

@end

swiftからObjective-Cを実行

プロジェクト作成時に自動で生成されているViewControllerで先ほど実装したGrayScaleメソッドを呼び出します。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var myImageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let image = myImageView.image;
        let gray = OpenCVSample.grayScale(image)
        myImageView.image = gray;

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

UIImageViewに紐づけた画像をグレースケールに変換して設定し直しています。

このとき、Objective-Cで設定したメソッド名が変わるので注意してください。今回は小文字になっているだけですが、メソッド名が長いと結構変更されてしまうようです。
どうやらSwiftからObjective-Cのメソッドを呼び出す場合、Xcodeがメソッド名を最適化してしまうようです。
(めちゃくちゃハマりました。)

続いてストーリーボードに画像を配置しましょう。
Main.storyboardを開きます。最初は空のViewControllerがあるのみなので、右側のユーティリティ領域のペインからImageViewを選択してストーリーボードのViewControllerにドラッグ&ドロップします。

ストーリーボードのImageViewとViewControllerのmyImageView変数を紐づけます。
@IBOutlet と記述された変数はストーリーボードと紐づけることができます。
ViewController.swiftを開きます。この時にoptionキーを押しながら開くとウインドウが左右分割して開くので紐付けが便利になります。
@IBOutlet が記述されている行の左端に白丸が表示されているのでそれをドラッグアンドドロップし、UIImageViewに紐付けます。

処理を行う画像をXcodeプロジェクトに追加します。これはXcodeにドラッグアンドドロップでいけます。

ストーリーボードのImageViewを選択し、右側のユーティリティ領域のペインから先ほど追加した画像を選択します。(今回だとcat.jpg)

するとストーリーボードに画像が表示されます。

ここでXcodeの実行ボタンを押しましょう。
シミュレータが立ち上がって、先ほどの画像がグレースケール変換されたものが無事表示されました。