You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 21:22:43