📖 一、前言
在很多 App 中,我们会需要检测人脸,例如:
- 拍照前检测是否有脸;
- 分析表情、判断是否微笑;
- 做人脸识别前的预处理;
- 视频或相机实时检测。
Google 的 ML Kit 提供了强大的人脸检测(Face Detection)能力,而 Flutter 社区封装了一个插件
👉 google_mlkit_face_detection
本文将带你完整了解并使用 google_mlkit_face_detection: ^0.13.1 来实现:
- 本地图片人脸检测;
- 实时检测思路;
- 常见问题与优化建议。
⚙️ 二、环境与依赖配置
- 添加依赖
在项目的 pubspec.yaml 文件中添加:
yaml
dependencies:
flutter:
sdk: flutter
google_mlkit_face_detection: ^0.13.1
image_picker: ^1.2.0 # 用于选择图片
执行:
yaml
flutter pub get
- Android 配置
✅ 修改 Gradle 配置
在 android/app/build.gradle 中:
groovy
android {
compileSdkVersion 35
defaultConfig {
minSdkVersion 21
}
}
✅ 添加权限
在 android/app/src/main/AndroidManifest.xml 中:
xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- iOS 配置
✅ 修改 Podfile
最低支持版本应为:
platform :ios, '15.5'
✅ 添加相机 / 相册权限说明
在 ios/Runner/Info.plist 中:
xml
<key>NSCameraUsageDescription</key>
<string>用于检测人脸</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>用于选择人脸图片</string>
🧠 三、插件原理简介
google_mlkit_face_detection 的底层并不是 Dart 自己检测人脸,而是通过 平台通道 (Platform Channel) 调用 Android / iOS 的原生 ML Kit。
工作流程:
matlab
Flutter (Dart)
↓ Platform Channel
Native (Android / iOS)
↓ 调用 Google ML Kit
↓ 返回检测结果
Flutter 绘制 UI
这种方式的好处是:
- 检测在设备端执行,速度快;
- 无需联网;
- 精度高、稳定性好。
💡 四、FaceDetectorOptions 参数说明
dart
final options = FaceDetectorOptions(
enableContours: true, // 是否检测人脸轮廓(眼睛、嘴唇等)
enableLandmarks: true, // 是否检测关键点(眼睛、鼻尖、耳朵等)
enableClassification: true,// 是否识别表情(如微笑、闭眼)
performanceMode: FaceDetectorMode.accurate, // 准确模式(相对较慢)
minFaceSize: 0.1, // 最小人脸占图片比例
);
这些参数的取舍决定性能与检测精度的平衡。
🧩 五、完整示例:检测图片中的人脸
以下是一个完整的 Flutter 示例页面:
dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'package:image_picker/image_picker.dart';
class FaceDetectionPage extends StatefulWidget {
@override
_FaceDetectionPageState createState() => _FaceDetectionPageState();
}
class _FaceDetectionPageState extends State<FaceDetectionPage> {
File? _image;
List<Face>? _faces;
late FaceDetector _faceDetector;
bool _busy = false;
@override
void initState() {
super.initState();
final options = FaceDetectorOptions(
enableContours: true,
enableLandmarks: true,
enableClassification: true,
performanceMode: FaceDetectorMode.accurate,
);
_faceDetector = FaceDetector(options: options);
}
@override
void dispose() {
_faceDetector.close();
super.dispose();
}
Future<void> _pickAndDetect() async {
final picker = ImagePicker();
final XFile? file = await picker.pickImage(source: ImageSource.gallery);
if (file == null) return;
setState(() {
_busy = true;
_image = File(file.path);
_faces = null;
});
final inputImage = InputImage.fromFile(_image!);
try {
final faces = await _faceDetector.processImage(inputImage);
setState(() => _faces = faces);
} catch (e) {
print('检测失败: $e');
} finally {
setState(() => _busy = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('人脸检测 Demo')),
body: Center(
child: _busy
? CircularProgressIndicator()
: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (_image != null)
SizedBox(
width: 300,
height: 300,
child: Stack(
fit: StackFit.expand,
children: [
Image.file(_image!, fit: BoxFit.cover),
if (_faces != null)
CustomPaint(painter: FacePainter(_faces!)),
],
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _pickAndDetect,
child: Text('选择图片并检测'),
),
const SizedBox(height: 10),
Text(_faces == null
? '未检测'
: '检测到 ${_faces!.length} 张人脸'),
],
),
),
);
}
}
class FacePainter extends CustomPainter {
final List<Face> faces;
FacePainter(this.faces);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..style = PaintingStyle.stroke
..strokeWidth = 3
..color = Colors.red;
for (var face in faces) {
canvas.drawRect(face.boundingBox, paint);
}
}
@override
bool shouldRepaint(covariant FacePainter oldDelegate) =>
oldDelegate.faces != faces;
}
🖼️ 运行效果
- 选择一张图片后,插件会检测其中的人脸;
- 检测到的人脸区域会用红框标出;
- 下方会显示检测到的人脸数量。
🎥 六、实时检测思路(Camera)
想实现类似抖音那样的实时检测,需要结合 camera 插件:
- 启动摄像头;
- 调用 controller.startImageStream();
- 每隔几帧或每 200ms 调用一次人脸检测;
- 使用 InputImage.fromBytes() 转换图像流;
- 在界面上叠加绘制检测框。
⚠️ 注意:
- 每帧检测会非常耗时;
- 建议降低帧率或检测频率;
- 处理时要注意图像旋转、镜像、比例。
🧱 七、常见问题与解决方案
问题 | 可能原因 | 解决办法 |
---|---|---|
iOS检测不到前置人脸 | 图像镜像 / 旋转角度错误 | 预处理图像方向或使用后置摄像头测试 |
Android 报错 removeFirst | 底层依赖冲突 | 升级 Gradle 与 Kotlin,清理缓存 |
实时检测卡顿 | 每帧都处理 | 设定检测间隔、关闭部分检测功能 |
检测不准确 | 模型限制 | 调整 minFaceSize 或开启 accurate 模式 |
资源未释放 | 未调用 close() | 页面销毁时调用 _faceDetector.close() |
⚡ 八、性能优化建议
目标 | 建议 |
---|---|
提高帧率 | 每隔 N 帧检测一次 |
提高精度 | 使用 FaceDetectorMode.accurate |
降低功耗 | 关闭不必要的检测项 |
减少误检 | 对 boundingBox 做过滤 |
稳定输出 | 对检测结果做平滑处理 |
🧭 九、总结
通过 google_mlkit_face_detection: ^0.13.1,我们可以:
✅ 快速实现本地人脸检测
✅ 离线检测、响应迅速
✅ 支持检测人脸框、关键点、表情等信息
但要注意:
- 插件依赖底层 ML Kit,不支持 Web;
- Android/iOS 环境需正确配置;
- 实时检测需做好性能优化。
🚀 十、后续方向
后续可以结合以下方向拓展:
- 使用 camera 实现实时检测;
- 将检测结果与 TensorFlow Lite 人脸识别模型结合;
- 在检测到人脸时自动拍照或触发动画效果;
- 实现人脸表情识别与情绪分析。
🧩 参考资料
- google_mlkit_face_detection 官方文档
- Google ML Kit 官方文档
- Flutter camera 插件