前言
最近在做一个考勤签到的系统,项目中需要人脸识别来做身份认证。这里来记录一下在react native中人脸检测模块的集成。
首先简单介绍一下项目中使用的到的库:
-
react-native-vision-camera:React Native Vision Camera 是一个用于构建 React Native 应用程序中与相机相关的功能的库。它提供了一种以高性能和可定制化的方式访问设备相机并捕获图像或视频的方法。该库是基于 iOS 和 Android 的本地相机 API 构建的,并为两个平台提供了统一的 API。它提供了各种功能,如实时图像处理、手动相机控制和自定义取景器叠加层。更多用例访问官网
-
Frame Processors:Frame Processors(帧处理器)是指对相机捕获的帧进行实时处理的功能模块。在 React Native Vision Camera中,可以使用 Frame Processors 来对相机捕获的帧进行自定义的处理。如:使用帧处理器将视频的每一帧中的人脸来进行检测。
-
vision-camera-face-detector:vision-camera-face-detector 是 React Native Vision Camera 库提供的一个人脸检测功能模块。它使用了 iOS 和 Android 平台的本地人脸检测算法,并提供了一个简单的 API,使开发人员可以轻松地在他们的应用程序中添加人脸检测功能。
集成步骤
1.安装react-native-vision-camera库
首先在项目中使用npm 或者yarn 安装react-native-vision-camera
#在你的项目,使用npm 安装
npm i react-native-vision-camera
cd ios
pod install
#或者使用yarn安装
yarn add react-native-vision-camera
cd ios
pod install
若要使用相机或麦克风,必须首先指定应用需要相机和麦克风权限。
苹果需要Info.plist
文件<dict>
标签中添加以下代码打开相机和麦克风权限,Info.plist
在~/ios/ios项目名称/Info.plist
目录
<!--相机权限-->
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) needs access to your Camera.</string>
<!--麦克风权限-->
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) needs access to your Microphone.</string>
安卓需要在AndroidManifest.xml
文件<manifest>
标签中添加以下代码
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
下面是一个react-native-vision-camera库的简单示例
import { useCameraDevices, Camera} from 'react-native-vision-camera';
import * as React from 'react';
import {useRef} from 'react';
export function FaceRecognitionPunch(props) {
const camara=useRef(null)
// 获取可用镜头
const devices = useCameraDevices();
// 使用前置摄像头
const device = devices.front;
return device != null && (
<Camera
ref={camara} //绑定ref
device={device} //绑定设备
isActive={true}
photo={true} //打开相机功能
frameProcessorFps={'auto'}
/>
) ;
}
2.使用Frame Processors帧处理器需要安装react-native-reanimated库
#使用yarn安装
yarn add react-native-reanimated
cd ios
pod install
3.安装vision-camera-face-detector人脸检测模块
#使用yarn安装
yarn add vision-camera-face-detector
cd ios
pod install
vision-camera-face-detector 提供了一个名为 useFaceDetector
的钩子,可以用于启用人脸检测功能。当使用 useFaceDetector
钩子启用人脸检测时,每次相机捕获到一帧画面时,该功能模块会自动检测画面中的人脸,并返回一个包含人脸信息的数组。具体使用示例看下面的完整代码
完整示例代码
import * as React from 'react';
import {runOnJS} from 'react-native-reanimated';
import { Platform} from 'react-native';
import { useCameraDevices, useFrameProcessor, Camera} from 'react-native-vision-camera';
import {scanFaces, Face} from 'vision-camera-face-detector';
import {useRef} from 'react';
export function FaceRecognitionPunch(props) {
const [hasPermission, setHasPermission] = React.useState(false);
//存储人脸信息
const [faces, setFaces] = React.useState([]);
//提示人脸的消息
const [msg, setMsg] = React.useState(null);
//用于打开相机等
const [isActiveVal, setIsActiveVal] = React.useState(true);
const camara=useRef(null)
//获取可用相机列表
const devices = useCameraDevices();
//使用前置摄像头
const device = devices.front;
React.useEffect( () => {
let facesArr = [];
facesArr = faces;
// faces为帧处理器获得到的人脸图片,从而进行人脸检测处理
if (facesArr.length > 0) {
let face = facesArr[0];
if (JSON.stringify(face.contours) == '{}') {
setMsg('人脸信息不全');
} else {
if (face.leftEyeOpenProbability == 1 && face.rightEyeOpenProbability == 1 && face.pitchAngle == 0 && face.rollAngle == 0) {
setMsg('面部遮挡');
} else {
if (face.leftEyeOpenProbability < 0.8 && face.rightEyeOpenProbability < 0.8) {
setMsg('请睁眼');
} else {
if (!(Math.abs(face.pitchAngle) < 6 && Math.abs(face.rollAngle) < 6 && Math.abs(face.yawAngle) <= 6)) {
setMsg('请正面朝向屏幕');
} else {
//关闭相机
setIsActiveVal(false);
//拍摄照片
takePicture().then(res=>{
console.log('成功',res)
}).catch()
}
}
}
}
}
}, [faces]);
React.useEffect(() => {
(async () => {
const status = await Camera.requestCameraPermission();
setHasPermission(status === 'authorized');
})();
}, []);
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
const scannedFaces = scanFaces(frame);
runOnJS(setFaces)(scannedFaces);
}, []);
// 拍摄人脸照片
const takePicture=async ()=>{
if (camara.current) {
let photo = null;
// 检测是ios还是安卓平台
if (Platform.OS === 'ios') {
photo = await camara.current.takePhoto({
qualityPrioritization: 'speed',
flash: 'off',
enableAutoRedEyeReduction: true,
});
} else {
photo = await camara.current.takeSnapshot({
quality: 80,
skipMetadata: true,
});
}
// photo.path 为拍摄的人脸照片地址,可以把照片传入后端进行人脸比对
let path = photo.path;
}
}
return device != null && hasPermission ? (
<Camera
ref={camara}
device={device}
isActive={isActiveVal}
photo={true}
frameProcessor={frameProcessor}
frameProcessorFps={'auto'}
/>
) : null;
}