代码改变世界

实用指南:Flutter 实现人脸检测 — 使用 google_mlkit_face_detection

2025-11-15 21:32  tlnshuju  阅读(51)  评论(0)    收藏  举报

一、前言

在很多 App 中,我们会需要检测人脸,例如:

  • 拍照前检测是否有脸;
  • 分析表情、判断是否微笑;
  • 做人脸识别前的预处理;
  • 视频或相机实时检测。

Google 的 ML Kit 提供了强大的人脸检测(Face Detection)能力,而 Flutter 社区封装了一个插件
google_mlkit_face_detection

本文将带你完整了解并使用 google_mlkit_face_detection: ^0.13.1 来实现:

  • 本地图片人脸检测;
  • 实时检测思路;
  • 常见问题与优化建议。

⚙️ 二、环境与依赖配置

  1. 添加依赖

在项目的 pubspec.yaml 文件中添加:

dependencies:
flutter:
sdk: flutter
google_mlkit_face_detection: ^0.13.1
image_picker: ^1.2.0   # 用于选择图片

执行:

flutter pub get

  1. Android 配置

✅ 修改 Gradle 配置

在 android/app/build.gradle 中:

android {
compileSdkVersion 35
defaultConfig {
minSdkVersion 21
}
}

✅ 添加权限

在 android/app/src/main/AndroidManifest.xml 中:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

  1. iOS 配置

✅ 修改 Podfile

最低支持版本应为:

platform :ios, ‘15.5’

✅ 添加相机 / 相册权限说明

在 ios/Runner/Info.plist 中:

<key>NSCameraUsageDescription</key>
<string>用于检测人脸</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>用于选择人脸图片</string>

三、插件原理简介

google_mlkit_face_detection 的底层并不是 Dart 自己检测人脸,而是通过 平台通道 (Platform Channel) 调用 Android / iOS 的原生 ML Kit。

工作流程:

Flutter (Dart)
↓  Platform Channel
Native (Android / iOS)
↓  调用 Google ML Kit
↓  返回检测结果
Flutter 绘制 UI

这种方式的好处是:

  • 检测在设备端执行,速度快;
  • 无需联网;
  • 精度高、稳定性好。

四、FaceDetectorOptions 参数说明

final options = FaceDetectorOptions(
enableContours: true,      // 是否检测人脸轮廓(眼睛、嘴唇等)
enableLandmarks: true,     // 是否检测关键点(眼睛、鼻尖、耳朵等)
enableClassification: true,// 是否识别表情(如微笑、闭眼)
performanceMode: FaceDetectorMode.accurate, // 准确模式(相对较慢)
minFaceSize: 0.1,          // 最小人脸占图片比例
);

这些参数的取舍决定性能与检测精度的平衡。


五、完整示例:检测图片中的人脸

以下是一个完整的 Flutter 示例页面:

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 {

_FaceDetectionPageState createState() => _FaceDetectionPageState();
}
class _FaceDetectionPageState extends State<FaceDetectionPage> {
  File? _image;
  List<Face>? _faces;
    late FaceDetector _faceDetector;
    bool _busy = false;
    
    void initState() {
    super.initState();
    final options = FaceDetectorOptions(
    enableContours: true,
    enableLandmarks: true,
    enableClassification: true,
    performanceMode: FaceDetectorMode.accurate,
    );
    _faceDetector = FaceDetector(options: options);
    }
    
    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);
      }
      }
      
      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);
        
        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);
        }
        }
        
        bool shouldRepaint(covariant FacePainter oldDelegate) =>
        oldDelegate.faces != faces;
        }

️ 运行效果

  • 选择一张图片后,插件会检测其中的人脸;
  • 检测到的人脸区域会用红框标出;
  • 下方会显示检测到的人脸数量。

六、实时检测思路(Camera)

想实现类似抖音那样的实时检测,需要结合 camera 插件:

  1. 启动摄像头;
  2. 调用 controller.startImageStream();
  3. 每隔几帧或每 200ms 调用一次人脸检测;
  4. 使用 InputImage.fromBytes() 转换图像流;
  5. 在界面上叠加绘制检测框。

⚠️ 注意:

  • 每帧检测会非常耗时;
  • 建议降低帧率或检测频率;
  • 处理时要注意图像旋转、镜像、比例。

七、常见问题与解决方案

问题可能原因解决办法
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 插件