这次使用uni-app框架开发一个APP,有一个刷脸功能,其实现原理是:通过livePusher对象(直播推流技术)实现视频预览和截屏,通过plus.zip.compressImage压缩图片上传至服务器
实现流程:调用手机摄像头创建直播推流 → 截图 → 压缩图片 → 上传图片到服务器 → 服务器调用百度人脸api → 百度api返回该图片与底图的相似度
1.调用手机摄像头,创建直播推流
利用直播推流技术开启摄像头,获取视频流
如果是nvue开发,可以直接使用live-pusher组件进行直播推流,如果是vue开发,则需要使用h5+的plus.video.LivePusher对象来获取,详情请查看https://uniapp.dcloud.io/component/live-pusher?id=live-pusher
下面以vue开发为例,vue开发有个不好的点,如果要在视频上展示其他内容,必须通过web-view嵌入其他html页面,cover-view始终都会在视频下面
进入页面的时候调用faceInit()方法,faceTip.html是显示在视频之上的其他内容,比如刷脸有一个类似于扫二维码一样的方框,
通过plus.video.createLivePusher创建直播推流,具体配置请参考文档:http://www.html5plus.org/doc/zh_cn/video.html
methods:{
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();
}
}
2.利用liverPusher对象的snapshot方法创建视频快照
methods:{
snapshotPusher() {
this.snapshTimeout = setTimeout(() => {
this.pusher.snapshot(
e => {
this.pusher.close();
//获取图片地址
var src = e.tempImagePath;
//压缩图片
this.getMinImage(src);
},
function(e) {
plus.nativeUI.alert('snapshot error: ' + JSON.stringify(e));
}
);
}, this.snapshotTimeoutNumber);
},
}
3.使用plus.zip.compressImage压缩图片
具体文档请参考:http://www.html5plus.org/doc/zh_cn/zip.html
methods:{
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);
}
);
},
}
以上是主要的技术点,下面贴出face.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
};
},
methods: {
faceHttp() {
this.faceAuth();
},
async faceAuth() {
//发送图片给服务器,根据自己的需求
toast('人脸认证中...', 'loading', 40000);
const data = { imgBase64: this.imgData };
try {
let res = await this.$http('auth-baidu-face', {
data
});
toast('认证成功');
this.navigateBack(2);
} catch (e) {
console.log('认证失败::', e);
this.tryHttp('人脸认证失败,需要重新认证吗');
}
},
pusherInit() {
const currentWebview = this.$mp.page.$getAppWebview();
this.pusher = plus.video.createLivePusher('livepusher', {
url: '',
top: '0px',
left: '0px',
width: '100%',
height: '100%',
position: 'absolute',
aspect: '9:16',
'z-index': 999
});
currentWebview.append(this.pusher);
this.pusher.preview();
},
faceInit() {
this.faceInitTimeout = setTimeout(() => {
this.pusherInit();
//覆盖在视频之上的内容,根据实际情况编写
this.scanWin = plus.webview.create('/hybrid/html/faceTip.html', '', {
background: 'transparent'
});
this.scanWin.show();
this.snapshotPusher();
uni.hideToast();
}, 500);
},
snapshotPusher() {
this.snapshTimeout = setTimeout(() => {
this.pusher.snapshot(
e => {
this.pusher.close();
this.scanWin.hide();
var src = e.tempImagePath;
this.getMinImage(src);
},
function(e) {
plus.nativeUI.alert('snapshot error: ' + JSON.stringify(e));
}
);
}, this.snapshotTimeoutNumber);
},
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();
};
reader.readAsDataURL(plus.io.convertLocalFileSystemURL(zipRes.target));
}, 1000);
},
function(error) {
console.log('Compress error!', error);
}
);
},
},
onLoad() {
toast('正在调用摄像头', 'loading');
//#ifdef APP-PLUS
this.faceInit();
//#endif
},
onHide() {
this.faceInitTimeout && clearTimeout(this.faceInitTimeout);
this.snapshTimeout && clearTimeout(this.snapshTimeout);
this.scanWin.hide();
}
};
</script>
<style lang="scss" scoped>
.img-data {
width: 100%;
height: auto;
}
</style>