Flutter人脸检测插件learning_face_detection的使用

Flutter人脸检测插件learning_face_detection的使用

ML Face Detection

使用ML Kit在Flutter中进行人脸检测的一个简单方法。通过ML Kit的人脸检测,我们可以在图像中检测到人脸,识别关键面部特征,并获取检测到的人脸轮廓。请注意:它只是检测人脸,而不是识别人。

由于它可以实时执行人脸检测,因此我们可以将其用于视频聊天、游戏或TikTok等应用程序,这些应用程序可以响应用户的表情。

为了更好地了解人脸检测的过程,包括标志点、轮廓和分类,请先阅读相关概念。

示例图片

Getting Started

将依赖项添加到您的Flutter项目:

$ flutter pub add learning_face_detection

或者在pubspec.yaml文件中添加:

dependencies:
  learning_face_detection: ^0.0.2

然后运行 flutter pub get

Usage

导入包:

import 'package:learning_face_detection/learning_face_detection.dart';
Input Image

输入图像作为InputImage实例传递,它是learning_input_image包的一部分。

您可以使用learning_input_image中的InputCameraView小部件作为默认实现,以处理来自相机/存储的图像(或图像流)并将其转换为InputImage格式。

以下是使用InputCameraView获取InputImage进行人脸检测的示例:

import 'package:learning_input_image/learning_input_image.dart';

InputCameraView(
  title: 'Face Detection',
  onImage: (InputImage image) {
    // 现在我们可以将输入图像馈送到人脸检测器
  },
)
Face Detection

获取InputImage后,我们可以通过调用FaceDetector实例的detect方法开始检测人脸:

FaceDetector detector = FaceDetector();
List<Face> result = await detector.detect(image);

FaceDetector实例化时带有以下默认参数:

FaceDetector detector = FaceDetector(
  mode: FaceDetectorMode.fast, // 检测模式:快速或准确
  detectLandmark: true,        // 是否检测标志点
  detectContour: true,         // 是否检测轮廓
  enableClassification: false, // 是否启用分类
  enableTracking: false,       // 是否启用跟踪
  minFaceSize: 0.15,          // 最小人脸大小
)

但是我们可以通过传递其他值来覆盖这些默认值。

参数 默认值
mode FaceDetectorMode.fast / FaceDetectorMode.accurate FaceDetectorMode.fast
detectLandmark false / true false
detectContour false / true false
enableClassification false / true false
enableTracking false / true false
minFaceSize 0.0 到 1.0 之间的任何值 0.15
Output

人脸检测过程的结果是一个Face对象列表,每个对象包含以下内容:

Rect boundingBox // 显示检测到的人脸的矩形

double headAngleY // 头部向右旋转的角度

double headAngleZ // 头部侧倾的角度

int? trackingId // 跟踪ID

double? smilingProbability // 笑脸的概率

double? leftEyeOpenProbability // 左眼睁开的概率

double? rightEyeOpenProbability // 右眼睁开的概率

Map<FaceLandmarkType, FaceLandmark> landmarks // 标志点列表

Map<FaceContourType, FaceContour> countours // 轮廓列表

FaceLandmark对象包含两种信息:类型和点。

FaceLandmarkType type
Offset point

以下是FaceLandmarkType列表:

LEFT_EYE
RIGHT_EYE
LEFT_EAR
RIGHT_EAR
LEFT_CHEEK
RIGHT_CHEEK
NOSE_BASE
MOUTH_LEFT
MOUTH_RIGHT
MOUTH_BOTTOM

每个FaceContour实例包含两种信息:类型和点。

FaceContourType type
List<Offset> points

以下是FaceContourType列表:

FACE
LEFT_EYE
RIGHT_EYE
LEFT_EYEBROW_TOP
LEFT_EYEBROW_BOTTOM
RIGHT_EYEBROW_TOP
RIGHT_EYEBROW_BOTTOM
NOSE_BRIDGE
NOSE_BOTTOM
LEFT_CHEEK
RIGHT_CHEEK
UPPER_LIP_TOP
UPPER_LIP_BOTTOM
LOWER_LIP_TOP
LOWER_LIP_BOTTOM
Face Painting

为了方便地从Face对象绘制到屏幕,我们提供了FaceOverlay,您可以将其传递给InputCameraViewoverlay参数。

FaceOverlay(
  size: size,
  originalSize: originalSize,
  rotation: rotation,
  faces: faces,
  contourColor: Colors.white.withOpacity(0.8),
  landmarkColor: Colors.lightBlue.withOpacity(0.8),
)
Dispose
detector.dispose();

Example Project

完整示例项目如下:

import 'package:flutter/material.dart';
import 'package:learning_face_detection/learning_face_detection.dart';
import 'package:learning_input_image/learning_input_image.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.lightBlue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
        primaryTextTheme: TextTheme(headline6: TextStyle(color: Colors.white)),
      ),
      home: ChangeNotifierProvider(
        create: (_) => FaceDetectionState(),
        child: FaceDetectionPage(),
      ),
    );
  }
}

class FaceDetectionPage extends StatefulWidget {
  [@override](/user/override)
  _FaceDetectionPageState createState() => _FaceDetectionPageState();
}

class _FaceDetectionPageState extends State<FaceDetectionPage> {
  FaceDetectionState get state => Provider.of(context, listen: false);

  FaceDetector _detector = FaceDetector(
    mode: FaceDetectorMode.accurate, // 准确模式
    detectLandmark: true,            // 检测标志点
    detectContour: true,             // 检测轮廓
    enableClassification: true,      // 启用分类
    enableTracking: true,            // 启用跟踪
  );

  [@override](/user/override)
  void dispose() {
    _detector.dispose(); // 释放资源
    super.dispose();
  }

  Future<void> _detectFaces(InputImage image) async {
    if (state.isNotProcessing) {
      state.startProcessing(); // 开始处理
      state.image = image;
      state.data = await _detector.detect(image); // 检测人脸
      state.stopProcessing(); // 结束处理
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return InputCameraView(
      title: 'Face Detection', // 标题
      onImage: _detectFaces,   // 图像回调
      resolutionPreset: ResolutionPreset.high, // 高分辨率预设
      overlay: Consumer<FaceDetectionState>(
        builder: (_, state, __) {
          if (state.isEmpty) {
            return Container();
          }

          Size originalSize = state.size!;
          Size size = MediaQuery.of(context).size;

          // 如果图像是从相册获取的
          // 图像显示尺寸缩放到360x360并保留纵横比
          if (state.notFromLive) {
            if (originalSize.aspectRatio > 1) {
              size = Size(360.0, 360.0 / originalSize.aspectRatio);
            } else {
              size = Size(360.0 * originalSize.aspectRatio, 360.0);
            }
          }

          return FaceOverlay(
            size: size,
            originalSize: originalSize,
            rotation: state.rotation,
            faces: state.data,
            contourColor: Colors.white.withOpacity(0.8), // 轮廓颜色
            landmarkColor: Colors.lightBlue.withOpacity(0.8), // 标志点颜色
          );
        },
      ),
    );
  }
}

class FaceDetectionState extends ChangeNotifier {
  InputImage? _image;
  List<Face> _data = [];
  bool _isProcessing = false;

  InputImage? get image => _image;
  List<Face> get data => _data;

  String? get type => _image?.type;
  InputImageRotation? get rotation => _image?.metadata?.rotation;
  Size? get size => _image?.metadata?.size;

  bool get isNotProcessing => !_isProcessing;
  bool get isEmpty => data.isEmpty;
  bool get isFromLive => type == 'bytes';
  bool get notFromLive => !isFromLive;

  void startProcessing() {
    _isProcessing = true;
    notifyListeners();
  }

  void stopProcessing() {
    _isProcessing = false;
    notifyListeners();
  }

  set image(InputImage? image) {
    _image = image;

    if (notFromLive) {
      _data = [];
    }
    notifyListeners();
  }

  set data(List<Face> data) {
    _data = data;
    notifyListeners();
  }
}

更多关于Flutter人脸检测插件learning_face_detection的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter人脸检测插件learning_face_detection的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用learning_face_detection插件进行人脸检测的示例代码。这个插件允许你利用机器学习模型在图像中检测人脸。

首先,确保你的Flutter项目已经设置好,并且在pubspec.yaml文件中添加了learning_face_detection依赖:

dependencies:
  flutter:
    sdk: flutter
  learning_face_detection: ^最新版本号  # 请替换为当前最新版本号

然后,运行flutter pub get来安装依赖。

接下来,编写Flutter代码来使用这个插件。以下是一个简单的示例,展示了如何从图像中检测人脸:

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:learning_face_detection/learning_face_detection.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FaceDetectionScreen(),
    );
  }
}

class FaceDetectionScreen extends StatefulWidget {
  @override
  _FaceDetectionScreenState createState() => _FaceDetectionScreenState();
}

class _FaceDetectionScreenState extends State<FaceDetectionScreen> {
  File? _imageFile;
  List<FaceDetectionResult>? _faceResults;

  final ImagePicker _picker = ImagePicker();

  Future<void> _pickImage(ImageSource source) async {
    final XFile? image = await _picker.pickImage(source: source);

    if (image != null) {
      final File imageFile = File(image.path);
      setState(() {
        _imageFile = imageFile;
        _detectFaces(imageFile);
      });
    }
  }

  Future<void> _detectFaces(File imageFile) async {
    try {
      final List<FaceDetectionResult> faceResults = await LearningFaceDetection.detectFaces(imageFile.path);
      setState(() {
        _faceResults = faceResults;
      });
    } catch (e) {
      print('Error detecting faces: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Face Detection'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            _imageFile != null
                ? Image.file(
                    _imageFile!,
                    width: 300,
                    height: 300,
                    fit: BoxFit.cover,
                    child: _faceResults != null
                        ? CustomPaint(
                            size: Size(300, 300),
                            painter: FacePainter(_faceResults!),
                          )
                        : null,
                  )
                : Text('No image selected.'),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () => _pickImage(ImageSource.gallery),
              child: Text('Pick Image from Gallery'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () => _pickImage(ImageSource.camera),
              child: Text('Take Photo'),
            ),
          ],
        ),
      ),
    );
  }
}

class FacePainter extends CustomPainter {
  final List<FaceDetectionResult> faceResults;

  FacePainter(this.faceResults);

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()
      ..color = Colors.red
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2.0;

    for (var face in faceResults) {
      final Rect faceRect = Rect.fromLTWH(
        face.boundingBox.left,
        face.boundingBox.top,
        face.boundingBox.width,
        face.boundingBox.height,
      );
      canvas.drawRect(faceRect, paint);
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return oldDelegate != this;
  }
}

在这个示例中,我们使用了image_picker插件来选择或拍摄照片。然后,我们使用learning_face_detection插件来检测选定图像中的人脸,并在检测到的人脸周围绘制红色矩形框。

请确保在你的pubspec.yaml文件中也添加image_picker依赖:

dependencies:
  image_picker: ^最新版本号  # 请替换为当前最新版本号

这个示例代码提供了一个基本的人脸检测功能,你可以根据需要进一步扩展和自定义。

回到顶部