flutter实时人脸检测
flutter real time face detection
我目前正在开发一个需要实时人脸检测的应用程序。现在我在应用程序中有 mlkit 库,我正在使用 firebase 人脸检测器。目前,每次我尝试从文件中检测人脸时都会产生错误:
DynamiteModule(13840): Local module descriptor class for com.google.android.gms.vision.dynamite.face not found.
至于实时部分,我尝试在 flutter 中使用 RepaintBoundary 获取相机小部件(几乎)每一帧的屏幕截图,并将其转换为二进制文件以进行人脸检测。但出于某种原因,每次我尝试截取相机小部件时,颤动都会崩溃。它适用于其他小部件。
在遇到这两个问题并花了很长时间尝试解决它们之后,我一直在考虑在 android/iOS 本机代码中只做应用程序的相机部分(我会用OpenCV 这样我就可以进行实时检测)。有没有一种方法可以使用平台通道在 kotlin 和 swift 中实现相机视图并将其导入 flutter 小部件?或者还有其他更简单的方法来实现吗?
我之前用 OpenCV 做过这个,我的解决方案是:
- 通过平台频道分别在 Android 和 iOS 上开始新的 Activity 或 ViewController。示例:
class FaceScanPlugin(val activity: Activity) : MethodCallHandler, PluginRegistry.ActivityResultListener {
var result: Result? = null
companion object {
@JvmStatic
fun registerWith(registrar: Registrar): Unit {
val channel = MethodChannel(registrar.messenger(), "com.example.facescan")
val plugin = BarcodeScanPlugin(registrar.activity())
channel.setMethodCallHandler(plugin)
registrar.addActivityResultListener(plugin)
}
}
override fun onMethodCall(call: MethodCall, result: Result): Unit {
if (call.method.equals("scan")) {
this.result = result
showFaceScanView()
} else {
result.notImplemented()
}
}
private fun showFaceScanView() {
val intent = Intent(activity, FaceScannerActivity::class.java)
activity.startActivityForResult(intent, 100)
}
override fun onActivityResult(code: Int, resultCode: Int, data: Intent?): Boolean {
if (code == 100) {
if (resultCode == Activity.RESULT_OK) {
return true
}
}
return false
}
}
请参阅 Flutter QR scanner plugin 了解如何导航至 Android activity 或 iOS 视图。
- 然后通过 Camera2 and AVFoundation 进行 OpenCV 实时人脸检测。
除此之外,如果您想将 android 或 iOS 嵌入到您的 Flutter 应用程序中,我想您可以尝试新的 AndroidView or UIKitView。
关于摄像头图像流的实时访问,我在另一个问题How to access camera frames in flutter quickly中回答了你要使用CameraController#startImageStream
import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: _MyHomePage()));
class _MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<_MyHomePage> {
dynamic _scanResults;
CameraController _camera;
bool _isDetecting = false;
CameraLensDirection _direction = CameraLensDirection.back;
@override
void initState() {
super.initState();
_initializeCamera();
}
Future<CameraDescription> _getCamera(CameraLensDirection dir) async {
return await availableCameras().then(
(List<CameraDescription> cameras) => cameras.firstWhere(
(CameraDescription camera) => camera.lensDirection == dir,
),
);
}
void _initializeCamera() async {
_camera = CameraController(
await _getCamera(_direction),
defaultTargetPlatform == TargetPlatform.iOS
? ResolutionPreset.low
: ResolutionPreset.medium,
);
await _camera.initialize();
_camera.startImageStream((CameraImage image) {
if (_isDetecting) return;
_isDetecting = true;
try {
// await doOpenCVDectionHere(image)
} catch (e) {
// await handleExepction(e)
} finally {
_isDetecting = false;
}
});
}
Widget build(BuildContext context) {
return null;
}
}
我目前正在开发一个需要实时人脸检测的应用程序。现在我在应用程序中有 mlkit 库,我正在使用 firebase 人脸检测器。目前,每次我尝试从文件中检测人脸时都会产生错误:
DynamiteModule(13840): Local module descriptor class for com.google.android.gms.vision.dynamite.face not found.
至于实时部分,我尝试在 flutter 中使用 RepaintBoundary 获取相机小部件(几乎)每一帧的屏幕截图,并将其转换为二进制文件以进行人脸检测。但出于某种原因,每次我尝试截取相机小部件时,颤动都会崩溃。它适用于其他小部件。
在遇到这两个问题并花了很长时间尝试解决它们之后,我一直在考虑在 android/iOS 本机代码中只做应用程序的相机部分(我会用OpenCV 这样我就可以进行实时检测)。有没有一种方法可以使用平台通道在 kotlin 和 swift 中实现相机视图并将其导入 flutter 小部件?或者还有其他更简单的方法来实现吗?
我之前用 OpenCV 做过这个,我的解决方案是:
- 通过平台频道分别在 Android 和 iOS 上开始新的 Activity 或 ViewController。示例:
class FaceScanPlugin(val activity: Activity) : MethodCallHandler, PluginRegistry.ActivityResultListener {
var result: Result? = null
companion object {
@JvmStatic
fun registerWith(registrar: Registrar): Unit {
val channel = MethodChannel(registrar.messenger(), "com.example.facescan")
val plugin = BarcodeScanPlugin(registrar.activity())
channel.setMethodCallHandler(plugin)
registrar.addActivityResultListener(plugin)
}
}
override fun onMethodCall(call: MethodCall, result: Result): Unit {
if (call.method.equals("scan")) {
this.result = result
showFaceScanView()
} else {
result.notImplemented()
}
}
private fun showFaceScanView() {
val intent = Intent(activity, FaceScannerActivity::class.java)
activity.startActivityForResult(intent, 100)
}
override fun onActivityResult(code: Int, resultCode: Int, data: Intent?): Boolean {
if (code == 100) {
if (resultCode == Activity.RESULT_OK) {
return true
}
}
return false
}
}
请参阅 Flutter QR scanner plugin 了解如何导航至 Android activity 或 iOS 视图。
- 然后通过 Camera2 and AVFoundation 进行 OpenCV 实时人脸检测。
除此之外,如果您想将 android 或 iOS 嵌入到您的 Flutter 应用程序中,我想您可以尝试新的 AndroidView or UIKitView。
关于摄像头图像流的实时访问,我在另一个问题How to access camera frames in flutter quickly中回答了你要使用CameraController#startImageStream
import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: _MyHomePage()));
class _MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<_MyHomePage> {
dynamic _scanResults;
CameraController _camera;
bool _isDetecting = false;
CameraLensDirection _direction = CameraLensDirection.back;
@override
void initState() {
super.initState();
_initializeCamera();
}
Future<CameraDescription> _getCamera(CameraLensDirection dir) async {
return await availableCameras().then(
(List<CameraDescription> cameras) => cameras.firstWhere(
(CameraDescription camera) => camera.lensDirection == dir,
),
);
}
void _initializeCamera() async {
_camera = CameraController(
await _getCamera(_direction),
defaultTargetPlatform == TargetPlatform.iOS
? ResolutionPreset.low
: ResolutionPreset.medium,
);
await _camera.initialize();
_camera.startImageStream((CameraImage image) {
if (_isDetecting) return;
_isDetecting = true;
try {
// await doOpenCVDectionHere(image)
} catch (e) {
// await handleExepction(e)
} finally {
_isDetecting = false;
}
});
}
Widget build(BuildContext context) {
return null;
}
}