Flutter如何实现人脸检测时自动触发拍照功能?
实现人脸检测自动触发拍照
核心思路
在相机预览的每一帧图像中执行人脸检测,当检测到人脸时自动调用takePicture方法,同时添加防重复触发逻辑避免连续拍照。
具体实现步骤
- 初始化相机并开启预览帧监听,对每一帧图像进行人脸检测
- 将
camera插件返回的CameraImage转换为google_ml_kit兼容的InputImage格式 - 检测到人脸后标记拍摄状态,调用拍照方法,可选停止图像流或设置间隔时间重新允许拍照
完整代码示例
import 'dart:async'; import 'package:camera/camera.dart'; import 'package:google_ml_kit/google_ml_kit.dart'; import 'package:flutter/material.dart'; class FaceAutoCapturePage extends StatefulWidget { const FaceAutoCapturePage({super.key}); @override State<FaceAutoCapturePage> createState() => _FaceAutoCapturePageState(); } class _FaceAutoCapturePageState extends State<FaceAutoCapturePage> { late CameraController _cameraController; bool _isPictureTaken = false; bool _isAlreadyCaptured = false; // 防重复拍照标记 final FaceDetectorService _faceDetectorService = FaceDetectorService(); @override void initState() { super.initState(); _initCamera(); } Future<void> _initCamera() async { // 获取前置相机 final cameras = await availableCameras(); final frontCamera = cameras.firstWhere( (camera) => camera.lensDirection == CameraLensDirection.front, ); // 初始化相机控制器 _cameraController = CameraController( frontCamera, ResolutionPreset.medium, enableAudio: false, ); await _cameraController.initialize(); // 监听预览帧,处理人脸检测 _cameraController.startImageStream((CameraImage image) async { if (_isAlreadyCaptured || _isPictureTaken) return; // 转换图像格式为人脸检测器可处理的类型 final inputImage = _convertCameraImageToInputImage(image); // 执行人脸检测 final faces = await _faceDetectorService.faceDetector.processImage(inputImage); if (faces.isNotEmpty) { _faceDetectorService.faceDetected = true; await takePicture(); _isAlreadyCaptured = true; // 如需间隔一段时间后允许再次拍照,取消下方注释 // Timer(const Duration(seconds: 5), () { // setState(() { // _isAlreadyCaptured = false; // _isPictureTaken = false; // }); // }); } else { _faceDetectorService.faceDetected = false; } }); } // 转换CameraImage为InputImage格式 InputImage _convertCameraImageToInputImage(CameraImage image) { final inputImageFormat = InputImageFormatValue.fromRawValue(image.format.raw); final planeData = image.planes.map( (Plane plane) => InputImagePlaneMetadata( bytesPerRow: plane.bytesPerRow, height: plane.height, width: plane.width, ), ).toList(); return InputImage.fromBytes( bytes: image.planes.first.bytes, metadata: InputImageMetadata( size: Size(image.width.toDouble(), image.height.toDouble()), // 根据相机方向调整旋转角度,前置相机通常设为90度 rotation: InputImageRotationValue.fromRawValue(90)!, format: inputImageFormat!, planeData: planeData, ), ); } Future<void> takePicture() async { if (_faceDetectorService.faceDetected) { try { await _cameraController.takePicture(); // 若使用自定义_cameraService,替换为对应方法 setState(() => _isPictureTaken = true); // 拍照完成后停止图像流,避免持续检测 await _cameraController.stopImageStream(); } catch (e) { print('拍照失败: $e'); } } } @override void dispose() { _cameraController.dispose(); _faceDetectorService.faceDetector.close(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: _isPictureTaken ? const Center(child: Text('照片已拍摄')) : CameraPreview(_cameraController), ); } } // 人脸检测服务类示例 class FaceDetectorService { final FaceDetector faceDetector = FaceDetector( options: FaceDetectorOptions( enableContours: false, enableClassification: false, ), ); bool faceDetected = false; }
注意事项
- 图像旋转角度:根据使用的相机(前置/后置)调整
InputImageRotation的值,否则可能导致人脸检测失效 - 资源释放:页面销毁时必须关闭人脸检测器和相机控制器,防止内存泄漏
- 防重复触发:通过
_isAlreadyCaptured变量避免短时间内连续拍照,可根据需求调整间隔时长
内容的提问来源于stack exchange,提问作者hafeezrana
相关产品推荐
相关产品推荐

