前言
闲来无事,学点东西充实一下自己。随手记录一下。本文使用了百度云的人脸对比的API,多个申请步骤。为什么要用纯前端来实现呢,懒呗还有啥。就想简单的实现一下,就不搞弯弯绕了。本次实现的主要是前端人脸识别并保存图片,然后调用百度云是API来完成对比,通过返回的相似度值来判断是否对比成功。文末附源码。其实也可以不用API,可以用python来完成模型训练,但那玩意我忘了,有时间再捡捡吧,社区搜搜应该有的。
页面布局:没啥好说的,就一个摄像头几个按钮
主要技术:vue2 + elementUI + tracking.js
本来是想用vue3的,但是好像有奇奇怪怪的bug,果断用了vue2。
创建项目
自己创建呗还等啥
然后npm i elementui啊axios啊
gan jin qu dong shou a
下载 trackingjs,别用npm,有坑!信我!戳这里=> 真的不骗你! (trackingjs.com)
下载完成之后解压有这么一个文件
选中它! 然后
ctrl+c
去到你项目的src
目录下面的asst
文件夹,然后ctrl+v
舒服了
接下来就是把这段源码放到你的页面中就可以了
<!--
🚀 Tip : tracking.js + 百度云 ===> 完成人脸识别
🥇 Author: LanYi
✨ Email : xiaoqi990727@163.com
✍ Data : 2023-03-22 14:24:21
-->
<template>
<div>
<div class="video-box">
<video id="video" width="320" height="240" preload autoplay loop muted></video>
<canvas id="canvas" width="320" height="240"></canvas>
</div>
<canvas id="screenshotCanvas" width="320" height="240"></canvas>
<div class="switch-button">
<el-row>
<el-button type="primary" @click="destroyed">关闭摄像头</el-button>
<el-button type="primary" @click="init">开始识别</el-button>
<el-button type="primary" @click="dayin">打印初始图</el-button>
<el-button type="primary" @click="dayinya">打印对比图</el-button>
<el-button type="primary" @click="getSimilarity">获取相似度</el-button>
</el-row>
</div>
<div>
<img :src="img" alt="">
<img :src="img1" alt="">
</div>
</div>
</template>
<script>
import '@/assets/tracking/build/tracking-min.js';
import '@/assets/tracking/build/data/face-min.js';
import axios from 'axios';
export default {
data () {
return {
trackerTask: null,
mediaStreamTrack: null,
video: null,
screenshotCanvas: null,
img: null,
img1: null,
length: null,
token: null
}
},
mounted () {
this.init();
this.getToken()
},
methods: {
// 初始化设置
init () {
this.video = this.mediaStreamTrack = document.getElementById('video');
this.screenshotCanvas = document.getElementById('screenshotCanvas');
let canvas = document.getElementById('canvas');
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('#video', tracker, { camera: true });
// 监听
tracker.on('track', event => {
// 检测出人脸 绘画人脸位置
context.clearRect(0, 0, canvas.width, canvas.height);
// rect.x, rect.y, rect.width, rect.height这四个参数表示左上角的坐标和框出来人脸的大小。
event.data.forEach(rect => {
context.strokeStyle = '#a64ceb';
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
context.font = '11px Helvetica';
context.fillStyle = "#fff";
context.fillText('x: ' + rect.x + 'px', rect.x + rect.width + 5, rect.y + 11);
context.fillText('y: ' + rect.y + 'px', rect.x + rect.width + 5, rect.y + 22);
});
// event.data.length长度代表检测几张人脸
this.length = event.data.length
});
},
// 获取相似度 ===>关键
async getSimilarity () {
const data = JSON.stringify([
{
"image": this.img.replace(/^data:image\/\w+;base64,/, ""),
"image_type": "BASE64",
"face_type": "LIVE",
"quality_control": "LOW",
"liveness_control": "HIGH"
},
{
"image": this.img1.replace(/^data:image\/\w+;base64,/, ""),
"image_type": "BASE64",
"face_type": "IDCARD",
"quality_control": "LOW",
"liveness_control": "HIGH"
}
])
const res = await axios({
url: `/ly/match?access_token=${this.token}`,
method: 'POST',
headers: { "content-type": "application/json" },
data
})
console.log('人脸对比结果 ======>', res.data)
if (!res.data.result) {
this.$message.error('人脸对比失败')
return
}
res.data.result.score > 80 && this.$message.success(`人脸对比通过,相似度为 ${res.data.result.score}`);
res.data.result.score < 80 && this.$message.error('人脸对比失败');
},
// 获取百度云 token
async getToken () {
const postData = {
url: `/xiaoqi/token?client_id=xxxxxx&client_secret=xxxxxx&grant_type=client_credentials`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
}
const res = await axios(postData)
this.token = res.data.access_token
},
// 获取人脸数据
getFaceData () {
// 没有识别到人脸直接返回
if (!this.length) return
// 绘制当前帧图片转换为base64格式
let canvas = this.screenshotCanvas;
let video = this.video;
let ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
let base64Img = canvas.toDataURL('image/jpeg');
return base64Img
},
// 初始图
dayin () {
this.img = this.getFaceData()
},
// 对比图
dayinya () {
this.img1 = this.getFaceData()
},
//关闭摄像头
destroyed () {
if (!this.mediaStreamTrack) {
return
}
this.mediaStreamTrack.srcObject.getTracks()[0].stop();
this.trackerTask.stop()
}
}
}
</script>
<style scoped>
/* 绘图canvas 不需显示隐藏即可 */
#screenshotCanvas {
display: none;
}
.video-box {
position: relative;
margin-left: 30px;
width: 320px;
height: 240px;
}
.switch-button {
margin-top: 30px;
margin-left: 30px;
}
video,
canvas {
position: absolute;
top: 0;
left: 0;
border: #000000 5px solid;
}
</style>
代码别直接跑啊,肯定会报错的。检查一下引入的路径啥的名字对不对啥的。还有,百度云的一些密钥啥的我都用
xxxxxx
来替换了。你需要去百度云拿你自己的!获取token那里留个心眼。
用下面这两个去替换一下
怎么创建我也不记得了,自己摸索吧,反正创建完要人脸识别验证一下,然后好像有一些可以白嫖的福利领一下,主要是搜索
人脸识别
然后就点进去,创建应用,就可以看见上面的页面了。好了就这样了,累了。本来想说一下具体代码的,但是发现这个好简单,还有挺多注释的,如果你看到这了就慢慢琢磨吧,加油秃头仔!
差点忘记了,还没完呢
纯前端解决会被浏览器报跨域的错误,我做了代理,直接复制粘贴过去就可以了。现在基本没什么问题了。
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
proxy: {
'/ly': {
target: 'https://aip.baidubce.com/rest/2.0/face/v3', //后台接口的服务地址
pathRewrite: { '^/ly': ''}
},
'/xiaoqi': {
target: 'https://aip.baidubce.com/oauth/2.0', //后台接口的服务地址
pathRewrite: { '^/xiaoqi': ''}
},
}
}
})
意外之喜
对比不通过的话就好好反思一下自己哈,是不是太帅了让接口堵住了!