公司的业务需求是用户在使用某个功能前,必须使用人脸识别,确保当前使用人是用户本人,防止某些功能乱用。后端用的是腾讯的人脸识别方案,这里只是前端的识别代码,保证人脸剧中,大小合适,有一个人脸以上
小程序代码,主要利用的是
wx.createVKSession
这个API来实现,样式部分可自行修改
这部分代码只是小程序前端识别的代码,真正的人脸比对代码是在后端,需要前端识别到人脸后上传到后端进行比对。
部分位置可根据业务需求要样式来修改,这里只是我自己调整的位置
wxml
html
<view class="title">{{verifyText}}</view>
<view class="container">
<image src="{{faceImg}}" wx:if="{{faceImg}}" class="faceImg" mode="widthFix"/>
<camera class="camera" device-position="front" flash="off"></camera>
</view>
js部分
javascript
let listener = null;
let videoCtx = null;
let VKSession = null;
let faceVerifyTime = null; //面容验证倒计时
Page({
data: {
faceImgHeight: 314,
faceImgWidth: 314,
face: {
origin: {
x: 0,
y: 0
},
size: {
width: 0,
height: 0
},
points:[]
},
verifyText:"请移动面容到框内",
isCentre:false, //是否面容在正中间
startVerify:false, //是否正在验证
faceImg:"", //面容图片地址
},
/**
* 生命周期函数--监听页面加载
*/
onLoad() {
this.getAuthSetting(); //获取权限
this.initFaceVerify()
},
getAuthSetting(){
wx.getSetting({
success :(res)=> {
if(!res.authSetting['scope.camera']){
wx.showModal({
title: '请允许获取摄像头权限',
showCancel:false,
complete: (modalRes) => {
if (modalRes.confirm) {
wx.openSetting({
success:(settingRes)=>{
if(!settingRes.authSetting['scope.camera']){
this.getAuthSetting()
}else{
wx.navigateBack()
}
}
})
}
}
})
}
}
})
},
initFaceVerify(){
videoCtx = null;
listener=null;
VKSession=null;
videoCtx = wx.createCameraContext();
let count = 0;
listener = videoCtx.onCameraFrame((frame) => {
count++;
if (count === 5) {
this.detectFace(frame);
count = 0;
}
});
VKSession = wx.createVKSession({
version: 'v1',
track: {
plane: {
mode: 1
},
face: {
mode: 2
}
}
});
VKSession.on('updateAnchors', (anchors) => {
// 有面容
console.log(anchors,'有面容')
if(this.data.startVerify){
return;
}
let anchor = anchors[0];
this.setData({
face: {
points: anchor.points,
origin: anchor.origin,
size: anchor.size
}
},()=>{
this.isFaceCentered()
})
})
VKSession.on('removeAnchors', (anchors) => {
// 面容消失
if(this.data.startVerify){
return;
}
this.setData({
verifyText:'请移动面容到框内',
isCentre:false,
face:{}
},()=>{
clearTimeout(faceVerifyTime)
faceVerifyTime = null;
})
})
setTimeout(() => {
// 直接开始
this.handleStart()
}, 500);
},
onUnload() {
VKSession.destroy();
},
picture(){
this.setData({
startVerify:true
},()=>{
clearTimeout(faceVerifyTime)
faceVerifyTime = null;
videoCtx.takePhoto({
quality:'original',
success:(e)=>{
//上传照片接口,图片换成远端url地址 自行替换
uploadImage(e.tempImagePath).then((res)=>{
this.setData({
faceImg:res
})
wx.showLoading({
title: '正在验证',
})
try {
// 执行后端分析人脸
api({
img:res
}).then((writeoffRes) => {
//识别成功
//自行处理识别成功结果
}).catch(err => {
wx.hideLoading();
wx.showModal({
title: err.msg,
showCancel:false,
confirmText:'重新核验',
complete: (res) => {
if (res.confirm) {
this.setData({
startVerify:false,
faceImg:"",
verifyText:'请移动面容到框内',
isCentre:false,
face:{}
},()=>{
this.handleStart()
})
}
}
})
})
} catch (error) {
console.log(error)
}
}).catch(()=>{
this.setData({
startVerify:false,
faceImg:"",
verifyText:'请移动面容到框内',
isCentre:false,
face:{}
},()=>{
this.handleStart()
wx.showToast({
title: '网络连接失败,请重试',
})
})
})
}
})
})
},
handleStart() {
VKSession.start((errno) => {
console.warn('VKSession.start errno', errno);
});
listener.start();
},
handleStop() {
listener.stop({
complete: (res) => {
console.warn('listener.stop', res);
}
});
VKSession.stop();
},
async detectFace(frame) {
// 获取面容
VKSession.detectFace({
frameBuffer: frame.data,
width: frame.width,
height: frame.height,
scoreThreshold: 0.8,
sourceType: 0,
modelMode: 2
});
},
isFaceCentered() {
// 判断面容是否在中间
if(!this.data.face.points){
return;
}
let points = this.data.face.points[43]; //位置
let size = this.data.face.size; //大小
if(points.x>0.65||points.x<0.4||points.y>0.65||points.y<0.35){
this.setData({
verifyText:'请移动面容到框内',
isCentre:false,
face:{}
},()=>{
clearTimeout(faceVerifyTime)
faceVerifyTime = null;
})
return
}else if(size.width>0.95||size.width<0.32){
this.setData({
verifyText:'请移动面容显示完整面容',
isCentre:false,
face:{}
},()=>{
clearTimeout(faceVerifyTime)
faceVerifyTime = null;
})
return
}
this.setData({
verifyText:'请保持不动',
isCentre:true
},()=>{
this.verifyCentre()
})
},
verifyCentre(){
// 开始验证面容
if(faceVerifyTime||this.data.startVerify){
return
}else{
faceVerifyTime = setTimeout(() => {
if(this.data.isCentre){
this.handleStop()
this.picture()
}else{
clearTimeout(faceVerifyTime)
faceVerifyTime = null;
}
}, 1500);
}
}
})
style
css
.container {
position: relative;
padding: 200rpx 0;
}
.title{
position: absolute;
width: 100%;
text-align: center;
padding-top: 100rpx;
font-size: 36rpx;
}
.camera{
width: 600rpx;
height: 600rpx;
border-radius: 50% 50%;
margin: 0 auto;
}
.faceImg{
width: 600rpx;
height: 600rpx;
border-radius: 50% 50%;
margin: 0 auto;
position: absolute;
z-index: 999;
}