Flutter实现:从图片URL检测人脸并裁剪头像
Flutter人脸检测并裁剪头像解决方案
1. 确认依赖与配置
首先确保使用google_mlkit_face_detection库,在pubspec.yaml中添加依赖:
dependencies: google_mlkit_face_detection: ^0.10.0 http: ^1.1.0 # 用于下载网络图片 image: ^4.1.3 # 用于裁剪图片
Android配置
在android/app/src/main/AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" />
在android/app/build.gradle中设置最小SDK版本:
android { defaultConfig { minSdkVersion 21 } }
iOS配置
在ios/Runner/Info.plist中添加权限描述:
<key>NSCameraUsageDescription</key> <string>需要相机权限进行人脸检测</string> <key>NSPhotoLibraryUsageDescription</key> <string>需要访问相册进行人脸检测</string>
2. 完整代码实现
步骤1:下载网络图片
import 'dart:typed_data'; import 'package:http/http.dart' as http; Future<Uint8List> downloadImage(String url) async { final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { return response.bodyBytes; } else { throw Exception('Failed to download image'); } }
步骤2:检测人脸并裁剪
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart'; import 'package:image/image.dart' as img; import 'dart:ui'; Future<img.Image?> cropFaceFromImage(String imageUrl) async { // 下载图片 final Uint8List imageBytes = await downloadImage(imageUrl); // 解码图片用于后续裁剪 final img.Image originalImage = img.decodeImage(imageBytes)!; // 创建InputImage final InputImage inputImage = InputImage.fromBytes( bytes: imageBytes, metadata: InputImageMetadata( size: Size(originalImage.width.toDouble(), originalImage.height.toDouble()), rotation: InputImageRotation.rotation0deg, // 根据图片实际旋转角度调整 format: InputImageFormat.bgra8888, bytesPerRow: originalImage.width * 4, ), ); // 初始化人脸检测器 final options = FaceDetectorOptions( performanceMode: FaceDetectorMode.accurate, minFaceSize: 0.15, // 调整最小人脸占比,太小的人脸会被忽略 ); final faceDetector = FaceDetector(options: options); // 执行检测 final List<Face> faces = await faceDetector.processImage(inputImage); await faceDetector.close(); // 释放资源 if (faces.isEmpty) return null; // 裁剪第一张人脸(多张人脸可自行扩展逻辑) final Face face = faces.first; // 转换相对坐标为实际像素坐标 final int left = (face.boundingBox.left * originalImage.width).toInt(); final int top = (face.boundingBox.top * originalImage.height).toInt(); final int width = (face.boundingBox.width * originalImage.width).toInt(); final int height = (face.boundingBox.height * originalImage.height).toInt(); // 裁剪并返回人脸图片 return img.copyCrop( originalImage, x: left.clamp(0, originalImage.width), y: top.clamp(0, originalImage.height), width: width.clamp(0, originalImage.width - left), height: height.clamp(0, originalImage.height - top), ); }
步骤3:UI中展示裁剪结果
// 在StatefulWidget的build方法中使用 FutureBuilder<img.Image?>( future: cropFaceFromImage('你的图片URL'), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasData) { return Image.memory(img.encodePng(snapshot.data!)); } else { return const Text('未检测到人脸'); } } else { return const CircularProgressIndicator(); } }, )
3. 常见问题排查
- 未检测到人脸:
- 调小
FaceDetectorOptions中的minFaceSize参数,比如设为0.1; - 检查
InputImage的rotation参数,尝试不同旋转值(如rotation90deg); - 切换
InputImageFormat为rgba8888试试。
- 调小
- 权限问题:确保iOS和Android的权限配置正确,网络图片需开启INTERNET权限。
- 内存泄漏:必须调用
faceDetector.close()释放检测器资源。
内容的提问来源于stack exchange,提问作者Harsh Rathod
相关产品推荐
相关产品推荐

