功能描述:
App端常用的刷脸验证功能,实现界面如下,当执行某操作时(如点击按钮),首先调用前置摄像头进行扫脸操作,拍照后上传到后台进行身份验证。
解决方案:
参考文章:https://blog.csdn.net/qq_31403519/article/details/106780327
(1)利用直播推流技术(h5+的plus.video.LivePusher)【http://www.html5plus.org/doc/zh_cn/video.html】开启摄像头,获取视频流;通过plus.video.createLivePusher创建直播推流;
(2)利用plus.webview.create将扫描框页面及扫描动画(xxx.html)覆盖在视频之上;
(3)利用liverPusher对象的snapshot方法创建视频快照;
(4)使用plus.zip.compressImage压缩图片;用法参考http://www.html5plus.org/doc/zh_cn/zip.html
(5)将base64图片发送给后台
完整代码【faceRec.vue】
<template>
<view>
<img :src="imgData" ref="img" class="img-data" />
</view>
</template>
<script>
export default {
data() {
return {
imgData: '',
pusher: null,
scanWin: null,
snapshotTimeoutNumber: 3000,
faceInitTimeout: null,
snapshTimeout: null
};
},
onLoad() {
uni.showToast({
title: "正在打开摄像头,请稍后",
icon: "none"
})
//#ifdef APP-PLUS
this.faceInit();
//#endif
},
onHide() {
this.faceInitTimeout && clearTimeout(this.faceInitTimeout);
this.snapshTimeout && clearTimeout(this.snapshTimeout);
this.scanWin.hide();
},
methods: {
// (5)将base64图片【this.imgData】发送给后台
faceHttp() {
// 省略后台请求
uni.navigateTo({
url: "/pages/code/code"
})
},
// (1)通过plus.video.createLivePusher创建直播推流
pusherInit() {
//获取当前窗口对象
const currentWebview = this.$mp.page.$getAppWebview();
//创建视频推流对象,url是视频上传到的服务器地址,不填表示不传视频
this.pusher = plus.video.createLivePusher('livepusher', {
url: '',
top: '0px',
left: '0px',
width: '100%',
height: '100%',
position: 'absolute',
aspect: '9:16',
'z-index': 999
});
// 将推流对象append到当前页面中
currentWebview.append(this.pusher);
this.pusher.preview();
},
faceInit() {
this.faceInitTimeout = setTimeout(() => {
this.pusherInit();
//覆盖在视频之上的内容,-比如扫描框
// (2)利用plus.webview.create将扫描框页面及扫描动画(xxx.html)覆盖在视频之上;
this.scanWin = plus.webview.create('/hybrid/html/scan.html', '', {
background: 'transparent'
});
// 显示窗口
this.scanWin.show();
this.snapshotPusher();
uni.hideToast();
}, 200);
},
// (3)利用liverPusher对象的snapshot方法创建视频快照
snapshotPusher() {
this.snapshTimeout = setTimeout(() => {
this.pusher.snapshot(
e => {
this.pusher.close();
this.scanWin.hide();
var src = e.tempImagePath;
// 使用plus.zip.compressImage压缩图片
this.getMinImage(src);
},
function(e) {
plus.nativeUI.alert('snapshot error: ' + JSON.stringify(e));
}
);
}, this.snapshotTimeoutNumber);
},
// (4)使用plus.zip.compressImage压缩图片
getMinImage(imgPath) {
plus.zip.compressImage({
src: imgPath,
dst: imgPath,
overwrite: true,
quality: 40
},
zipRes => {
setTimeout(() => {
var reader = new plus.io.FileReader();
reader.onloadend = res => {
var speech = res.target.result; //base64图片
console.log(speech.length);
this.imgData = speech;
//将图片发送给后台
this.faceHttp();
};
//一定要使用plus.io.convertLocalFileSystemURL将target地址转换为本地文件地址,否则readAsDataURL会找不到文件
reader.readAsDataURL(plus.io.convertLocalFileSystemURL(zipRes.target));
}, 1000);
},
function(error) {
console.log('Compress error!', error);
}
);
},
},
};
</script>
<style lang="scss" scoped>
.img-data {
width: 100%;
height: auto;
}
</style>
【scan.html】
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>人脸采集</title>
<style>
</style>
<link rel="stylesheet" href="css/style.css" />
<script src="js/jquery.min.js"></script>
</head>
<body>
<div class="center1">
<p id="info">正在检测...</p>
</div>
<div id="faceImg" class="center">
<div id="finger_box">
<img id="line" src="img/line1.png" style="opacity :0.5" />
</div>
</div>
</body>
<script>
var $info=$('#info'),$line=$('#line');
$(function(){
setTimeout(
"$info.stop().text('请眨眨眼')"
,2000)
$line.stop().show();
});
</script>
</html>
【style.css】
@CHARSET "UTF-8";
html {
width: 100%;
height: 100%;
font-size: 100%;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
font-family: "微软雅黑", 'microsoft yahei', Arial, sans-serif;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background: url('../img/face4.png') no-repeat center center;
background-size: cover;
opacity: 0.9
}
img {
border: 0 none;
max-width: 100%;
height: auto;
width: auto;
-ms-interpolation-mode: bicubic;
vertical-align: middle;
}
.box {
width: 100%;
height: 100%;
}
#finger {
width: 100%;
height: 180px;
position: absolute;
text-align: center;
}
#finger_box {
width: 100%;
height: 100%;
position: relative;
}
#line {
width: 100%;
height: 27px;
position: absolute;
top: 50%;
left: 50%;
margin: -6px 0 0 -50%;
display: none;
-webkit-animation: line 1.4s infinite;
animation: line 1.4s infinite;
}
#info {
width: 100%;
height: 30px;
line-height: 30px;
color: #000;
font-size: 3.6em;
font-family: "微软雅黑", 'microsoft yahei', Arial, sans-serif;
}
@keyframes line {
0% {
transform: translateY(-400px);
}
50% {
transform: translateY(400px);
}
100% {
transform: translateY(-400px);
}
}
@-webkit-keyframes line {
0% {
-webkit-transform: translateY(-400px);
}
50% {
-webkit-transform: translateY(400px);
}
100% {
-webkit-transform: translateY(-400px);
}
}
.center {
position: absolute;
top: calc(50% - 80px);
left: 50%;
width: 100%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
text-align: center;
z-index: 999999;
}
.center1 {
margin-top: 200px;
width: 100%;
text-align: center;
z-index: 999999;
}
.overLoading {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #f5f5f5;
opacity: 0.5;
z-index: 1000;
}
.layoutLoading {
display: none;
position: absolute;
top: 40%;
left: 40%;
width: 20%;
height: 20%;
z-index: 1001;
text-align: center;
}