CSDN话题挑战赛第2期
uni-app项目中使用tracking.js人脸识别:前端技术分享
说在前面
针对uni-app项目中倒计时拍照、对齐人脸按钮拍照等拍照方式,导致的识别效率下降,人脸信息捕捉不完全,进而浪费计算资源等问题。本文将tracking.js应用到uni-app项目中,可以在识别出人脸的前提下,将图像信息传输到后端进行比对。
引言
首先介绍下tracking.js与uni-app:
-
tracking.js是一个独立的JavaScript库,用于跟踪从相机实时收到的数据。跟踪的数据既可以是颜色,也可以是人,也就是说我们可以通过检测到某特定颜色,或者检测一个人体/脸的出现与移动,来触发JavaScript 事件。
-
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
「uni-app项目中使用tracking.js人脸识别」
最近想把web端使用tracking.js的人脸识别应用在uni-app项目中,那当然是直接使用Ctrl+C Ctrl+V大法,显而易见的报错了,明明在web端就好用,在uni-app中就不好用呢?经过不断地试错与对比终于发现了问题,原来是uni-app封装了一些同名媒体组件,而这些组件和原生的用法不一样(吐血)
问题复现
分别在web端和uni-app端项目中运行下列代码,web端正常运行,uni-app报错了,结果如图一、图二所示:
this.video = document.getElementById('video');
let canvas = document.getElementById('canvas');
console.log(this.video);
console.log(canvas);
图一 web端中运行结果
图二 uni-app中运行结果
可以看出到document.getElementById获取到的video与canvas标签不一致,显示为uni-video和uni-canvas,即uni-app中的已经封装好的video与canvas。而video与canvas标签则如图三所示:
图三video与canvas标签
解决方法
根据图三,将封装好的video与canvas进行拆解。
拆解:
this.video = document.getElementById('video').children[0].children[0];
let canvas = document.getElementById('canvas').children[0];
console.log(this.video);
console.log(canvas);
拆解后:
拆解后的标签就可以对应上了,接下来用之前方法测试一下,成功搞定!
其中需要注意的一点是uni-app中的video参数需要注意一下。
<video id="video" objectFit="cover" style="width:690px;height:690px" :controls="false" :show-center-play-btn="false" :autoplay="true" :loop="true">
:controls=“false”:不显示操作按钮
:show-center-play-btn=“false”:不显示play按钮
:autoplay=“true”:开启自动播放
:loop=“true”:开启轮播
源代码
face.vue文件
<template>
<view class="container">
<image class="bg" src="../static/images/login/digHole.png"></image>
<view class="video-box">
<video id="video" objectFit="cover" style="width:690px;height:690px" :controls="false" :show-center-play-btn="false" :autoplay="true" :loop="true">
</video>
<canvas id="canvas" style="width:690px;height:690px"></canvas>
<canvas id="canvas_2" style="width:690px;height:690px"></canvas>
</view>
</view>
</template>
<script>
import "../assets/tracking-min.js";
import "../assets/face-min.js";
export default {
data() {
return {
saveArray: {},
trackerTask: null,
mediaStreamTrack: null,
video: null,
screenshotCanvas: null,
uploadLock: true // 上传锁
}
},
mounted() {
this.init();
},
methods: {
// 初始化设置
init() {
if (!(document.getElementById('video') &&
document.getElementById('video').children[0] !== null &&
document.getElementById('video').children[0].children[0] !== null &&
document.getElementById('canvas') &&
document.getElementById('canvas').children[0] !== null &&
document.getElementById('canvas_2') &&
document.getElementById('canvas_2').children[0] !== null)) {
} else {
this.video = this.mediaStreamTrack = document.getElementById('video').children[0].children[0];
this.screenshotCanvas = document.getElementById('canvas_2').children[0];
let myVideo = document.getElementById('video').children[0].children[0];
let canvas = document.getElementById('canvas').children[0];
let context = canvas.getContext('2d');
// 固定写法
let tracker = new window.tracking.ObjectTracker('face');
tracker.setInitialScale(4);
tracker.setStepSize(2);
tracker.setEdgesDensity(0.1);
//摄像头初始化
this.trackerTask = window.tracking.track(myVideo, tracker, {camera: true});
let _this = this;
let saveArray = {};
tracker.on('track', function (event) {
// 检测出人脸 绘画人脸位置
context.clearRect(0, 0, 690, 690);
event.data.forEach(function (rect) {
context.strokeStyle = '#0764B7';
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
saveArray.x = rect.x;
saveArray.y = rect.y;
saveArray.width = rect.width;
saveArray.height = rect.height;
});
//识别范围
let canvas1 = document.getElementById('canvas').children[0];
let context1 = canvas.getContext('2d');
context1.strokeStyle = "#69fff1";
context1.moveTo(150, 60);
context1.lineTo(520, 60);
context1.lineTo(520, 580);
context1.lineTo(150, 580);
context1.lineTo(150, 60);
context1.stroke();
// event.data.length长度为多少代表检测几张人脸
setInterval(() => {
if (
saveArray.x > 140 &&
saveArray.x + saveArray.width < 550 &&
saveArray.y > 40 &&
saveArray.y + saveArray.height < 600 &&
saveArray.width < 260 &&
saveArray.height < 500
) {
// this.getPhoto();
if (_this.uploadLock && event.data.length) {
//上传图片
_this.screenshotAndUpload();
}
for (let key in saveArray) {
delete saveArray[key];
}
}
}, 2000);
});
}
},
// 上传图片
screenshotAndUpload() {
// 上锁避免重复发送请求
this.uploadLock = false;
// 绘制当前帧图片转换为base64格式
let canvas2 = this.screenshotCanvas;
let video = this.video;
let ctx = canvas2.getContext('2d');
ctx.clearRect(0, 0, 690, 690);
// ctx.drawImage(video, 0, 0, 690, 690);
ctx.drawImage(video, 180,90,300,510,0,0,300,510);
let base64Img = canvas2.toDataURL('image/jpeg');
ctx.clearRect(0, 0, 690, 690);
// 打印出 base64Img
console.log('base64Img:', base64Img)
// this.faceRecognition(base64Img)
// 请求接口成功以后打开锁
// this.uploadLock = true;
},
//关闭摄像头
async destroyed() {
if (!this.mediaStreamTrack) {
return
}
this.mediaStreamTrack.srcObject.getTracks()[0].stop();
this.trackerTask.stop()
},
}
}
</script>
<style scoped lang="scss">
/* 绘图canvas 不需显示隐藏即可 */
#screenshotCanvas {
display: none;
}
.bg{
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1;
}
.container{
height: 1080px;
display: flex;
/* 水平垂直居中 */
justify-content: center;
align-items: center;
}
.video-box {
margin-top: 80px;
margin-right: 10px;
width: 690px;
height: 690px;
}
video, #canvas,#canvas_2 {
position: absolute;
border: #000000 5px solid;
}
</style>
效果图
总结
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,所以我感觉很多在web端可以实现的代码,在uni-app也可以复用,将来会再挖掘一些在uni-app中使用的插件。