人脸识别主要工作量在后端,我这边只负责前端代码。
// 静态
<div style={{ color: theme.tc2, fontSize: 22, marginBottom: 15 }}>
{!faceCheck ? '人脸登录' : '认证失败,请重试'}
</div>
<video
width='400px'
height='400px'
autoPlay
ref={videoRef}
></video>
<canvas
ref={canvasRef}
width='400px'
height='400px'
style={{ display: 'none' }}
></canvas>
<img
ref={imageRef}
src=''
alt='人脸识别'
style={{ display: 'none' }}
/>
{faceCheck ? (
<div
style={{
position: 'absolute',
top: 105,
left: 20,
height: 400,
width: 400,
backgroundColor: 'rgba(0,0,0,.4)',
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Button
type='primary'
style={{
width: 120,
marginBottom: 15,
}}
onClick={() => {
setFaceCheck(false)
openMedia()
getPhotoUel()
}}
>
继续人脸识别
</Button>
</div>
) : (
''
)}
const videoRef = useRef(null)
const canvasRef = useRef(null)
const imageRef = useRef(null)
const [video, setVideo] = useState<any>()
const [canvas, setCanvas] = useState<any>()
const [image, setImage] = useState<any>()
const timer = useRef<any>(null) // 定时器
useEffect(() => {
setCanvas(canvasRef.current)
setVideo(videoRef.current)
setImage(imageRef.current)
if (video && faceLogin) {
// 开启摄像头
openMedia()
// 获取头像 base64,轮询调登录接口
getPhotoUrl()
}
if (!faceLogin) {
timer.current && clearInterval(timer.current)
}
return () => {
timer.current && clearInterval(timer.current)
}
}, [videoRef, video, faceLogin, canvas, canvasRef])
接下来是一些用到的方法??navigator.mediaDevices.getUserMedia(),这个方法本地代码测试没问题,放到线上或者测试环境的话会报错,所以我们得捕捉这次错误,不然项目或崩掉。导致错误产生的原因就是这个方法对环境的要求比较严格:1、开启了 HTTPS 的域。2、使用?file:/// ?协议打开的本地文件。3、开启 Chrome 的相应参数。解决getUserMedia报错的原文链接??解决报错。
// 打开摄像头
const openMedia = () => {
const constraints = {
video: { width: 500, height: 500 },
audio: false, // 音频不需要开启
}
//获得video摄像头
if (
navigator.mediaDevices === undefined ||
navigator.mediaDevices.getUserMedia === undefined
) {
notification.error({
message: '您的电脑暂不支持该功能,请使用其他方式登录',
})
timer.current && clearInterval(timer.current)
stopCapture()
setFaceCheck(false) // 人脸识别失败
setFaceLogin(false) // 隐藏人脸识别登录界面
setLoginMode('form') // 切换登录方式为账号密码
return
}
const promise = navigator?.mediaDevices?.getUserMedia(constraints)
promise
.then((mediaStream: any) =>
video.srcObject = mediaStream
video.play()
})
.catch(() => {
notification.error({
message: '您的电脑暂不支持该功能,请使用其他方式登录',
})
timer.current && clearInterval(timer.current)
stopCapture() // 停止摄像机
setFaceCheck(false)
setFaceLogin(false)
setLoginMode('form')
})
}
//停止摄像机
const stopCapture = () => {
if (!video.srcObject) return
const stream = video.srcObject
const tracks = stream.getTracks()
tracks.forEach((track: any) => {
track.stop()
})
}
// 获取头像的 base64,轮询调登录接口
const getPhotoUrl = () => {
let num = 0
timer.current = setInterval(() => {
num++
const ctx = canvas.getContext('2d')
ctx.drawImage(video, 0, 0, 500, 500)
// toDataURL --- 可传入'image/png'---默认, 'image/jpeg'
const img = canvas.toDataURL() // img 是获取到的base64格式的字符串
// 这里调接口 login(img)
video.pause()
stopCapture()
clearInterval(timer.current)
})
.catch(() => {
if (num >= 3) {
clearInterval(timer.current)
setFaceCheck(true)
image.src = img
video.pause()
stopCapture()
}
})
}, 2000)
}
上面的代码就是前端需要做的主要内容,不过有一下几点需要注意:
1、由于参数是base64格式的,所以参数传递一定要放在body中,拼接在url中会报: 431 Request Header Fields Too Large。
2、用的是百度智能云的话需要注意人脸对比的分数,默认46就识别通过了(后端配置),这是很危险的
?3、对navigator.mediaDevices.getUserMedia()的处理,不然本地测试没问题发布后会导致各种问题。
4、不管什么情况,离开人脸识别界面的时候一定要记得关闭摄像头!!!!
|