2020年6月13日:一部加筆・修正しました。
2020年4月27日、OpenCV にこんな PR が現れました。
Objc binding by komakai · Pull Request #17165 · opencv/opencv
これまで、OpenCV には Java のラッパーが含まれていたため、Android で簡単に OpenCV を利用することができましたが、iOS、macOS では Objective-C、Swift で使うために自分で C++ を呼び出すためのラッパーを書く必要がありました。そこで、@komakai さんによって提案されたのがこの PR でした。
そして今日 2020年6月9日、その PR が無事に master ブランチへマージされ、自分で Objective-C++ を書くことなく、Objective-C、Swift で使うことができるようになりました🎉
あ!!!!!!!
— treastrain / Tanaka Ryoga (@treastrain) June 8, 2020
Merged!!!!!!!!!!
Objc binding by komakai · Pull Request #17165 · opencv/opencvhttps://t.co/uQLcKlBxoN pic.twitter.com/zQvA29BNSl
今回は iOS プロジェクトで Swift から OpenCV を使うデモを行ってみたいと思います。
環境
$ swift --version
Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53)
$ cmake --version
cmake version 3.17.3
$ python --version
Python 2.7.18
$ xcode-select --version
xcode-select version 2373
- macOS Catalina 10.15.5 (19F101)
- Xcode 11.5 (11E608c)
OpenCV をダウンロードする
OpenCV 4.4 に含まれると思われますが、記事執筆時点では Release に含まれていないので、git clone で master ブランチのものを持ってきます。
$ xcode-select --install
$ git clone https://github.com/opencv/opencv.git
OpenCV.framework をビルドする
続いて OpenCV.framework をビルドします。
./build_framework.py <outputdir>
を実行する必要があるので、私の環境では以下のようにしました。時間がかかるのでゆっくり待ちましょう。
$ cd opencv/platforms/ios
$ ./build_framework.py .
Using IPHONEOS_DEPLOYMENT_TARGET=8.0
Using iPhoneOS ARCHS=['armv7', 'armv7s', 'arm64']
Using iPhoneSimulator ARCHS=['i386', 'x86_64']
... つづく
CMAKE_Swift_COMPILER が見つからないエラー
私ははじめ CMake のバージョンを 3.15.5 で実行していたのですが、No CMAKE_Swift_COMPILER could be found.
となってしまい、フレームワークをビルドすることができませんでした。PR の中でもこのエラーは認識されていて、しばらくは 3.16 以降が必要となっていましたが、その後最小サポートバージョンが 3.15 に引き下げられました。でもまだエラーが出る気がするんだけど…?
このエラーについて私は 3.17 を使うことで回避しました。
Xcode プロジェクトに opencv2.framework を導入
<outputdir>
で指定したディレクトリに opencv2.framework
が出来ているので、Xcode プロジェクトに導入します。libc++.tbd も追加します。
Swift で opencv2 を import
ここで Swift で import opencv2
をします。またコードを書いていきます。自分で Objective-C++ のラッパーを書かなくていいのはものすごく楽…。これまでは Objective-C++ を書いて、 Bridging Header も書いてからようやく Swift を書く…という流れでしたが、より簡単になりました。
import UIKit
import opencv2
class ViewController: UIViewController {
@IBOutlet weak var srcImageView: UIImageView!
@IBOutlet weak var dstImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let image = UIImage(named: "サンプル画像")!
self.srcImageView.image = image
self.dstImageView.image = self.convertColor(source: image)
}
func convertColor(source srcImage: UIImage) -> UIImage {
let srcMat = Mat(uiImage: srcImage)
let dstMat = Mat()
Imgproc.cvtColor(src: srcMat, dst: dstMat, code: .COLOR_RGB2GRAY)
return dstMat.toUIImage()
}
}
unrecognized selector sent to instance
しかしながら、記事執筆時点では let srcMat = Mat(uiImage: srcImage)
の部分で unrecognized selector sent to instance
の実行時エラーが発生します。
実装は opencv/modules/imgcodecs/misc/objc/ios/Mat+Converters.mm
にあり、そこで UIImageToMat()
を呼び出しているわけですが…
"Other Linker Flags" に -all_load
を追加する
unrecognized selector sent to instance
の実行時エラーが発生する問題があるとしていましたが、"Other Linker Flags" に -all_load
を追加する必要がありました。
(Thanks @komakai ! Mat initWithUIImage:
does not work (Objective-C / Swift) · Issue #17532 · opencv/opencv)
実行結果
自分で Objective-C++ のラッパーを書くことなく、OpenCV を使うことができました!!
他のサンプル
フレームワークをビルドする際に指定した には opencv2.framework の他に samples があり、その中に ColorBlobDetection と FaceDetection の2つが入っています。Sign して opencv2.framework のパスを指定するだけで iOS App を Run できるので、こちらを試してみるのもいいですね。