修复react-native-vision-camera-face-detector人脸框偏移问题
React Native Vision Camera人脸检测Bounding Box偏移的跨设备解决方案
人脸检测框偏移到右下的核心问题,是相机原始帧的坐标系与Skia预览窗口的坐标系没有完成正确映射,只单纯计算缩放比例会忽略旋转、镜像、黑边偏移这些跨设备变量。以下是通用解决步骤:
1. 获取预览窗口与帧的真实尺寸
先通过Camera组件的onLayout事件拿到预览窗口的实际渲染尺寸,同时在FrameProcessor里获取相机帧的原始尺寸与方向:
import { useRef, useState } from 'react'; import { Camera } from 'react-native-vision-camera'; const CameraComponent = () => { const cameraRef = useRef(null); const [previewSize, setPreviewSize] = useState({ width: 0, height: 0 }); // 获取预览窗口实际渲染尺寸 const handleCameraLayout = (e) => { const { width, height } = e.nativeEvent.layout; setPreviewSize({ width, height }); }; return ( <Camera ref={cameraRef} style={{ flex: 1 }} onLayout={handleCameraLayout} // 其他相机配置(如cameraType、format等) /> ); };
2. 处理坐标系的旋转与镜像
相机帧的方向可能和预览窗口不一致(比如竖屏时帧默认旋转90度),前置摄像头还会有镜像翻转,这两步是跨设备适配的关键:
// 在FrameProcessor中处理人脸坐标转换 const frameProcessor = useFrameProcessor((frame) => { 'worklet'; const faces = detectFaces(frame); // 调用人脸检测插件方法 const { width: frameWidth, height: frameHeight, orientation } = frame; const { width: previewWidth, height: previewHeight } = previewSize; faces.forEach(face => { let { x, y, width: faceWidth, height: faceHeight } = face.boundingBox; // 1. 处理帧旋转:根据相机方向调整坐标 if (orientation === 'portrait') { // 竖屏场景下帧默认旋转90度,需互换x/y并修正范围 const tempX = x; x = frameHeight - y - faceHeight; y = tempX; // 同步互换人脸框的宽高 [faceWidth, faceHeight] = [faceHeight, faceWidth]; } // 2. 前置摄像头镜像翻转X坐标 if (cameraRef.current?.cameraType === 'front') { x = frameWidth - x - faceWidth; } // 3. 计算缩放比例与黑边偏移 const frameRatio = frameWidth / frameHeight; const previewRatio = previewWidth / previewHeight; let scale, offsetX = 0, offsetY = 0; if (frameRatio > previewRatio) { // 帧宽比预览宽,按高度适配,左右留黑边 scale = previewHeight / frameHeight; offsetX = (previewWidth - frameWidth * scale) / 2; } else { // 帧高比预览高,按宽度适配,上下留黑边 scale = previewWidth / frameWidth; offsetY = (previewHeight - frameHeight * scale) / 2; } // 转换为预览窗口的最终坐标 const finalX = x * scale + offsetX; const finalY = y * scale + offsetY; const finalWidth = faceWidth * scale; const finalHeight = faceHeight * scale; // 用Skia绘制人脸框:Canvas.drawRect(finalX, finalY, finalWidth, finalHeight) }); }, [previewSize]);
3. 验证关键变量
- 确认
frame.orientation的实际取值(不同设备可能返回portrait/landscape-left等,需根据返回值调整旋转逻辑) - 前置摄像头的
cameraType判断要准确,避免镜像逻辑错误 - 预览尺寸必须取Camera组件实际渲染的尺寸,不能直接用屏幕尺寸(Camera可能存在padding或布局调整)
这样处理后,坐标会自动适配不同设备的屏幕尺寸、相机分辨率与方向,无需硬编码常量值。
内容的提问来源于stack exchange,提问作者Srikanth
相关产品推荐
相关产品推荐

