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 插件
相关推荐
ajassi20005 分钟前
开源 Objective-C IOS 应用开发(二)Xcode安装
ios·objective-c·xcode
付十一31 分钟前
更新!Figma MCP + Cursor:大前端时代的UI到代码自动化
android·前端·ai编程
wa的一声哭了40 分钟前
hf中transformers库中generate的greedy_search
android·java·javascript·pytorch·深度学习·语言模型·transformer
YungFan43 分钟前
SwiftUI-WebView 全面指南
ios·swiftui
猪哥帅过吴彦祖1 小时前
Flutter 从入门到精通:深入 Navigator 2.0 - GoRouter 路由完全指南
android·flutter·ios
lichong9511 小时前
【macOS 版】Android studio jdk 1.8 gradle 一键打包成 release 包的脚本
android·java·前端·macos·android studio·大前端·大前端++
Kapaseker2 小时前
Kotlin 跨平台开发中的权衡
android·ios·kotlin
恋猫de小郭3 小时前
来了解一下,为什么你的 Flutter WebView 在 iOS 26 上有点击问题?
android·前端·flutter
newchenxf3 小时前
AndroidStudio版本和AGP版本和gradle版本以及kotlin gradle plugin版本关系梳理 2025
android·开发语言·kotlin
CocoaKier3 小时前
苹果上线App Store Web版本,以后浏览外区更方便了
ios·apple