如何在Flutter中实现这类自拍相机遮罩效果?

我想要在Flutter中制作这类相机遮罩用于自拍,让面部区域保持清晰聚焦,其余区域呈现透明效果,请问该如何实现?
Flutter实现自拍面部清晰遮罩方案
1. 引入必要依赖
要实现这个效果,需要用到相机预览和面部检测的插件,在pubspec.yaml中添加:
dependencies: camera: ^0.10.5+5 google_mlkit_face_detection: ^0.10.0
执行flutter pub get完成依赖安装。
2. 初始化相机与实时面部检测
先获取前置相机并初始化控制器,然后监听预览帧,实时检测面部位置:
import 'package:camera/camera.dart'; import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart'; late CameraController _cameraController; final _faceDetector = FaceDetector( options: FaceDetectorOptions( enableContours: false, enableClassification: false, ), ); Rect? _faceRect; // 初始化相机 Future<void> initCamera() async { final cameras = await availableCameras(); final frontCamera = cameras.firstWhere((cam) => cam.lensDirection == CameraLensDirection.front); _cameraController = CameraController(frontCamera, ResolutionPreset.medium); await _cameraController.initialize(); // 监听预览帧,检测面部 _cameraController.startImageStream((image) async { final inputImage = InputImage.fromBytes( bytes: image.planes.first.bytes, metadata: InputImageMetadata( size: Size(image.width.toDouble(), image.height.toDouble()), rotation: InputImageRotationValue.fromRawValue(frontCamera.sensorOrientation)!, format: InputImageFormatValue.fromRawValue(image.format.raw)!, bytesPerRow: image.planes.first.bytesPerRow, ), ); final faces = await _faceDetector.processImage(inputImage); if (faces.isNotEmpty) { setState(() => _faceRect = faces.first.boundingBox); } }); }
3. 自定义遮罩绘制
创建CustomPainter来绘制全屏半透明遮罩,并挖空面部区域:
class FaceMaskPainter extends CustomPainter { final Rect? faceRect; final Size previewSize; final Size screenSize; FaceMaskPainter({this.faceRect, required this.previewSize, required this.screenSize}); @override void paint(Canvas canvas, Size size) { // 绘制全屏半透明遮罩 final maskPaint = Paint() ..color = Colors.black.withOpacity(0.7) ..style = PaintingStyle.fill; canvas.drawRect(Offset.zero & size, maskPaint); if (faceRect != null) { // 转换面部坐标适配屏幕尺寸 final scaleX = screenSize.width / previewSize.width; final scaleY = screenSize.height / previewSize.height; final scaledFace = Rect.fromLTWH( faceRect!.left * scaleX, faceRect!.top * scaleY, faceRect!.width * scaleX, faceRect!.height * scaleY, ); // 挖空面部区域,露出下方相机预览 canvas.drawRect(scaledFace, Paint()..blendMode = BlendMode.clear); } } @override bool shouldRepaint(FaceMaskPainter oldDelegate) => oldDelegate.faceRect != faceRect; }
4. 组合组件展示
把相机预览和遮罩层叠加,放在页面中:
@override Widget build(BuildContext context) { final screenSize = MediaQuery.of(context).size; return Scaffold( body: Stack( children: [ CameraPreview(_cameraController), CustomPaint( size: screenSize, painter: FaceMaskPainter( faceRect: _faceRect, previewSize: _cameraController.value.previewSize!, screenSize: screenSize, ), ), ], ), ); }
额外注意事项
- Android端要在
AndroidManifest.xml中添加相机权限:<uses-permission android:name="android.permission.CAMERA" /> - iOS端在
Info.plist中添加:<key>NSCameraUsageDescription</key><string>需要相机权限进行自拍</string> - 可以根据需求调整遮罩透明度、面部区域的圆角(把
drawRect换成drawRRect即可)
内容的提问来源于stack exchange,提问作者wolfsoft Developer
相关产品推荐
相关产品推荐

