Flutter 实现人脸检测 — 使用 google_mlkit_face_detection

📖 一、前言

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

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

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

👉 google_mlkit_face_detection

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

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

⚙️ 二、环境与依赖配置

  1. 添加依赖

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

yaml 复制代码
dependencies:
  flutter:
    sdk: flutter
  google_mlkit_face_detection: ^0.13.1
  image_picker: ^1.2.0   # 用于选择图片

执行:

yaml 复制代码
flutter pub get

  1. 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" />

  1. 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 插件:

  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 插件
相关推荐
●VON8 小时前
Flutter 鸿蒙插件适配实战:用 device_screen_brightness 2.0.0 控制并监听屏幕亮度
flutter·华为·harmonyos
天空之城--10 小时前
Android逆向安全合规接单指南
android·安全
消失的旧时光-194312 小时前
Android 系统层扫盲 09:AMS、ATMS、WMS、PMS 到底分别管什么?
android·wms·pms·ams·aosp·atms
Godikov12 小时前
Android 系统级设备应用踩坑实录:sharedUserId 签名、SDK 授权失败 -4、开机自启与 U 盘 OTA 升级
android
IT毕设实战小研15 小时前
基于大数据的国内主要农作物产量趋势分析与可视化
android·java·大数据·django·课程设计
风早爽太16 小时前
Flutter 开发笔记:share_plus 分享插件
笔记·flutter
●VON16 小时前
Flutter 鸿蒙插件适配实战:用 boot_time_plugin 1.0.0 读取启动时间与运行时长
flutter·华为·harmonyos
企业数字化笔记16 小时前
固定资产历史数据怎么导入系统?Excel模板、字段映射和数据校验
android·java·数据库·后端
龙之叶16 小时前
Android出海系列-GMS认证介绍
android
潮族大Z17 小时前
Android性能优化:启动、内存、卡顿的一站式排查手册
android