🌆
[Flutter] MethodChannelでOpenCVを使ってみよう!
上記GIFのようにFlutterでOpenCVを活用し、画像処理の方法について説明しようと思います。
(本記事はiOS側の動作を前提にしており、Android版のコードは含まれていません。)
1.MethodChannelとは?
詳細はドキュメントに記載されていますが、大雑把に表現すると「ネイティブ(iOS/Android)のメソッドを非同期で呼び出す
」処理のことです。
2.大まかな処理の流れ
画像データを文字型に変換し処理します。なぜなら、画像データを直接MethodChannelで取り扱うことができないからです。
2-1.Dart側
- 画像データ -> ByteData に変換する
ByteData imageData = await rootBundle.load('images/icon.jpeg');
- ByteData -> Uint8List に変換する
Uint8List list = Uint8List.view(imageData.buffer);
- Uint8List -> String(Base64) に変換する
String base64 = base64Encode(list);
- String(Base64) をMethodChannelでネイティブ側に渡す
static const platform = const MethodChannel('samples.flutter.dev/image');
String result = await platform.invokeMethod('getBase64', base64);
2-2.ネイティブ側(Swift)
- String(Base64) -> Data に変換する
let encodedBase64 = Data(base64Encoded: parameters)
- Data -> UIImage に変換する
let convert = UIImage(data: encodedBase64!)
- UIImage を OpenCV で画像変換する
let image = OpenCVManager.gray(convert)
- UIImage(変換済み) -> Data に変換する
let jpegData = image!.jpegData(compressionQuality: 1)
- Data -> String(Base64) に変換する
let base64 = jpegData!.base64EncodedString()
- String(Base64) をMethodChannelでDart側に渡す
result(base64)
3.プログラム
3-1.全体
3-2.Dart側
static const platform = const MethodChannel('samples.flutter.dev/image');
以下略
Future<String> _processOpenCVWithMethodChannel() async {
ByteData imageData = await rootBundle.load('images/icon.jpeg');
String base64 = base64Encode(Uint8List.view(imageData.buffer));
String result = await platform.invokeMethod('getBase64', base64);
return result;
}
3-3.Swift側
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel(name: "samples.flutter.dev/image",
binaryMessenger: controller.binaryMessenger)
methodChannel.setMethodCallHandler(
{
(call: FlutterMethodCall, result: FlutterResult) -> Void in
guard call.method == "getBase64" else {
result(FlutterMethodNotImplemented)
return
}
let parameters = call.arguments as! String
// String(Base64) -> Data
let encodedBase64 = Data(base64Encoded: parameters)
// Data -> UIImage
let convert = UIImage(data: encodedBase64!)
let image = OpenCVManager.gray(convert)
// UIImage -> (JPEG)Data
let jpegData = image!.jpegData(compressionQuality: 1)
// Data -> String(Base64)
let base64 = jpegData!.base64EncodedString()
result(base64)
}
)
まとめ
OpenCVはC++製
のため、dart:ffiが活用できます。
既存ネイティブアプリをFlutterでリプレースする場合、MethodChannelの方が仕事量が少ないため楽に見えるがパフォーマンス面や保守性を考えるとFFIの方が最適です。
ただしcameraパッケージでリアルタイムに画像処理する場合、FFIはエラーを吐き実装できません。そのため、MethodChannelで実装する手法も理解していて損はないと思います。
参考文献
スクラップ
Discussion