FlutterのmacOSアプリからC++のOpenCVを呼び出す
概要
macOS上のFlutterから、C++のOpenCVをFFI経由で呼び出す設定です。Flutter3でmacOSのアプリもstableとなったようですが、Flutter2のときに動作確認した手順なので、Flutter2(あえてFlutter3を避ける必要はないと思いますが)でも動作する思います。
環境
本記事での実行環境です。
> sw_vers
ProductName: macOS
ProductVersion: 12.4
> flutter --version
Flutter 3.1.0-9.0.pre • channel dev • https://github.com/flutter/flutter.git
Framework • revision f28e570c8c (2 weeks ago) • 2022-06-14 13:39:33 -0500
Engine • revision 74ee6b5afd
Tools • Dart 2.18.0 (build 2.18.0-165.1.beta) • DevTools 2.14.0
Flutter自体は、brewなどでインストールできるので、インストールしてください。
brew install flutter
手順
1. プロジェクト作成
Flutterのプロジェクトを作成して、サンプルのアプリが起動ができるか確認します。
flutter create --platforms macos .
flutter run
問題なく起動できれば、以下のUIが確認できるはずです。
2. OpenCVのxcframework生成
OpenCVのソースから、xcframeworkを生成します。OpenCV付属のコマンドを実行するだけで生成してくれます。
git clone --depth 1 https://github.com/opencv/opencv.git
python3 opencv/platforms/apple/build_xcframework.py --macos_archs x86_64 --build_only_specified_archs --out ./build_xcframework
ビルドが終了すると、build_xcframework
ディレクトリにopencv2.xcframework
が生成されているはずです。それをRunner.xcodeprojがあるディレクトリへコピーします。Runner.xcodeprojはflutter createで生成されるディレクトリにあります。
3. OpenCVのC++コード作成
C++にてCV_VERSIONを呼び出す以下のデモ関数を作成し、my_opencv.cppとして保存します。ここではmain.dartと同じlibディレクトリに保存します。
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
extern "C" {
__attribute__((visibility("default"))) __attribute__((used))
const char* version() {
return CV_VERSION;
}
}
4. FFIのコード作成
FFIとして呼び出すDartのコードを以下のように作成し、my_opencv.cppと同じディレクトリに保存します。
import 'dart:ffi' as ffi;
import 'dart:io';
import 'package:ffi/ffi.dart';
typedef _CVersionFunc = ffi.Pointer<Utf8> Function();
typedef _VersionFunc = ffi.Pointer<Utf8> Function();
ffi.DynamicLibrary _openDynamicLibrary() {
return ffi.DynamicLibrary.process();
}
ffi.DynamicLibrary _lib = _openDynamicLibrary();
final _VersionFunc _version =
_lib.lookup<ffi.NativeFunction<_CVersionFunc>>('version').asFunction();
String opencvVersion() {
return _version().toDartString();
}
5. Runner.xcodeprojの編集
Runner.xcodeprojを起動して、以下2つの操作をします。
- Frameworksにopencv2.xcframeworkを追加
- RunnerのGeneralでAdd Filesからopencv2.xcframeworkを追加
- Do Not Embedを選択
- OpenCVのC++コードの追加
- Runnerの下にmy_opencv.cppを追加
- Create folder references(デフォルト)を選択してFinishで追加
この時点で以下の画像のチェック部分と同じようになります。
6. FFIの追加
pubspec.yamlにffiを追加します。
ffi: ^2.0.1
7. OpenCVの呼び出し
main.dartを修正して、作成したデモ関数であるopencvVersion()を呼び出します。
以下のようにimportでmy_oepncvをロードすれば、opencvVersion()関数を呼び出せるようになるので、適当なボタン(以下だとShow version)を追加して、クリックするとopencvVersion()を呼び出すように編集すると、以下のようにOpenCVのバージョンが表示されると思います。
import 'my_opencv.dart';
最後に
FlutterでのFFIについては、昔から苦労されている方が多いですが、公開されている記事などは限られているので、同じことをやろうとしてる人は、mediumだったり、zennだったりで同じ記事を読んだのではないかと思います。自分もそうでした。時期や課題が違ったためか、同じ手順を試したのですが、なかなかうまくいかず、今回の記事の手順となりました。Flutterのtemplateを使用する手順などでもうまくいくなど、他のやり方についても知りたいので、知っている方がいれば教えて下さい。また、この手法もFlutter、Dart、FFIのバージョンが新しくなった場合は、そのまま適用できない可能性はあるので、その際も教えていただけると助かります。
Discussion