0%

vue中实现人脸识别


2020年的第一篇博客,手把手教你在vue中使用百度AI开放平台的百度人脸识别能力

开始敲代码之前,先做好准备工作

百度智能云

1、先去百度智能云注册一个账号

官方网站

2、创建人脸识别应用

进入页面后,在侧边栏选择人脸识别,在应用列表中创建一个新的应用,填写【应用名称】和【应用描述】,其他的使用默认值就可以了

3、获取秘钥

应用创建成功后,记录下自己的API Key、Secret Key

根据百度文档的API,第一次需要讲API Key、Secret Key传过去,用来获取Access Token,之后每一次请求都将这个token传递过去就可以了

4、创建人脸库

新建应用后,在人脸库管理中新增一个库,用来保存人脸识别的图片,这里图片就不贴出来了

至此,需要准备的东西已经准备好了

Node服务端

服务端的基本东西都要先引入进来,常用的就是express、bodyParser、axios、fs、qs,跨域也顺便处理一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var express = require('express');

var bodyParser = require('body-parser');

var axios = require('axios');

var fs = require('fs');

var qs = require('querystring');

var app = express();

app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
app.use(bodyParser.json({limit : "50mb"}));

app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Credentials", "true");
res.header("Access-Control-Allow-Headers", "Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, X-Requested-By, If-Modified-Since, X-File-Name, X-File-Type, Cache-Control, Origin");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
next();
});

用于后期需要传入图片,默认的大小为2048Kb左右,所以我们需要稍微调大一点

1、获取Access Token的接口

1
2
3
4
5
6
7
8
9
10
11
12
// 人脸识别-获取Access Token
app.post('/getToken',function(req,res){
const param = qs.stringify({
'grant_type': 'client_credentials',
'client_id': '你的client_id',
'client_secret': '你的client_secret'
});
axios.post('https://aip.baidubce.com/oauth/2.0/token', param).then((msg) => {
// 获取access_token
res.send(msg.data)
})
})

2、注册人脸库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
app.post('/initFace',function(req,res){

// 请求接口
var url = 'https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add?access_token=' + req.body.access_token
// 请求的图片数据

// 请求数据
var data = {
image_type: 'BASE64',
image: req.body.img,
group_id: 'ceshiGroup', // 之前注册人脸管理库的名字
user_id: 'csing' , // 这张图片的id
}

axios({
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
url: url,
data: qs.stringify(data),
}).then((msg)=>{
console.log(msg.data)
res.send(msg.data)
})

})

3、监测人脸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
app.post('/checkFace',function(req,res){

// 请求接口
var url = 'https://aip.baidubce.com/rest/2.0/face/v3/search?access_token=' + req.body.access_token
// 请求的图片数据

// 请求数据
var data = {
image_type: 'BASE64',
image: req.body.img,
group_id_list: 'ceshiGroup', // 之前注册人脸管理库的名字
liveness_control: 'HIGH' // 活体监测
}

axios({
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
url: url,
data: qs.stringify(data),
}).then((msg)=>{
res.send(msg.data)
})

})

主要就是这三个核心的代码,用来获取Token,注册人脸和识别人脸

前端部分

人脸识别分为两部分的

人脸注册和人脸识别

这两种分别用两种不同的方式

  1. 一种是input的图片上传方式来注册人脸识别库
  2. 另一种是调用照相机自动识别人脸进行第二步的人脸识别

这样不一样的需求就都满足到了

上传图片到人脸识别库

基本的思路是这样的

进入页面后,执行两部操作

  1. 获取Access_token并保存

  2. 初始监听图片选择,这样做的目的是用户点击input后,拍照或者选择照片,可以识别到用户的动作,将图片自动处理保存

直接看看具体的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<template>
<div class="hello">
<div>该页面为初始化识别库,添加识别人脸</div>
<br><br>
<input type="file" capture='camera' accept='image/*'>
<br><br>
<button @click="postFace">上传人脸识别库</button>

</div>
</template>

<script>
export default {
name: 'HelloWorld',
data() {
return {
access_token: '',
imgbase64: ''
}
},
methods: {
// 初始监听图片选择
initListenMsg(){
var inputs = document.querySelectorAll('input[type=file]');
var _this = this

inputs[0].onchange = function() {
var file = document.querySelector('input').files[0];
var reader = new FileReader();
// 文件读取成功完成时触发
reader.onload = function(e){
// onload事件的回调函数接受一个事件对象,该对象的target.result就是文件的内容
_this.imgbase64 = e.target.result.replace(/^data:image\/\w+;base64,/, "");
};
reader.readAsDataURL(file);
}
},
// 初始化调用Token
getToken(){
this.$axios.post('http://192.168.50.35:3000/getToken',{}).then((res)=>{
console.log(res)
this.access_token = res.data.access_token
})
},
// 添加人脸
postFace(){
this.$axios.post('http://192.168.50.35:3000/initFace',{
access_token: this.access_token,
img: this.imgbase64
}).then((res)=>{
if(res.data.error_code == 0){
alert('上传百度云AI人脸库管理成功')
}else{
alert('人脸已存在,请勿重复添加')
}
})
},
},
mounted() {
this.initListenMsg();
this.getToken();
},

}
</script>

人脸识别

图片上传到人脸库中了,接下来就要实验一下,人脸识别是否可以识别到库里面自己的照片

注册人脸库的时候,相机并没有像以前在其他的地方看到的人脸识别那样,有一个框框,自动识别到人脸后拍照上传,具体要怎么做呢,来看看思路

需要用到一个插件,tracking.js, 所以第一步先 npm install tracking 安装

接下里,解释一下这个插件应该怎么使用

现在dom中创建两个元素

1
2
<video width="320" height="240" ref="videoDom" id="video" preload autoplay loop muted></video>
<canvas width="320" height="240" ref="canvasDOM"></canvas>

这里的video是用来展示视频流的,也就是摄像头调用后,在video中可以看到我们的脸

canvas则是用来绘制识别人脸的框框,所以这两个元素我们需要使用定位重叠起来

tracking核心功能

解释一下核心的代码,完整的代码再末尾会贴出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 这一步就是用来开启摄像头的,tracking的插件已经帮我们封装好了
tracking.track(this.video, this.tracker, { camera: true });

// 初始化tracking参数,官方文档没有解释是干嘛用的,先照这些
this.tracker = new tracking.ObjectTracker("face");
this.tracker.setInitialScale(4);
this.tracker.setStepSize(2);
this.tracker.setEdgesDensity(0.1);

// 这里启动监听,也就是检查是否有人脸
this.tracker.on("track", event => {
// 将event的方法传递过去
this.onTracked(event);
});

// 如果是读取视频,可以用trackerTask.stop trackerTask.run来暂停、开始视频
this.trackerTask = tracking.track(this.video, this.tracker);

再看看监听的核心功能有哪些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 onTracked(event){
// 画框框
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
event.data.forEach(rect => {
this.context.lineWidth = 1;
this.context.strokeStyle = "#a64ceb";
this.context.strokeRect(rect.x, rect.y, rect.width, rect.height);
this.context.font = "11px Helvetica";
this.context.fillStyle = "#fff";
// 如果有数据,说明有人脸了
if (event.data.length > 0) {
console.log('监测到人脸')
}
});

}

完整代码

摄像头的调用已经实现了,接下来对人脸进行截图,识别,就和之前注册人脸库一样的逻辑了,这里就不多讲了,直接贴完整代码吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
<template>
<div>
<div class="user-icon">
<video width="320" height="240" ref="videoDom" id="video" preload autoplay loop muted></video>
<canvas width="320" height="240" ref="canvasDOM"></canvas>
</div>

<div>{{loding}}</div>
<div class="button" @click="initTracker">假设我是个按钮,点击之后我要人脸识别了</div>
</div>
</template>

<script>
require('tracking/build/tracking-min.js')
require('tracking/build/data/face-min.js')
// 嘴巴等特征,后期可添加
// require('tracking/build/data/mouth-min.js')
// require('tracking/build/data/eye-min.js')
//var objects = new tracking.ObjectTracker(['face', 'eye', 'mouth']);
// require('tracking/examples/assets/stats.min.js')

export default {
name: 'testTracking',
data() {
return {
// 记录拍照到了几次
count: 0,
isdetected: '请您保持脸部在画面中央',
loding: ''
}
},
methods: {
// 初始化racker
initTracker(){
// alert('进来了')
// alert(navigator.mediaDevices)
// 启用摄像头,这一个是原生调用摄像头的功能,不写的话有时候谷歌浏览器调用摄像头会失败
navigator.mediaDevices
.getUserMedia({video: true,audio: true})
.then(this.getMediaStreamSuccess)
.catch(this.getMediaStreamError)

this.context = this.canvas.getContext('2d')

// 初始化tracking参数
this.tracker = new tracking.ObjectTracker("face");
this.tracker.setInitialScale(4);
this.tracker.setStepSize(2);
this.tracker.setEdgesDensity(0.1);
this.tracker.on("track", event => {
this.onTracked(event);
});

// tracking启用摄像头,这里我选择调用原生的摄像头
// tracking.track(this.video, this.tracker, { camera: true });

// 如果是读取视频,可以用trackerTask.stop trackerTask.run来暂停、开始视频
this.trackerTask = tracking.track(this.video, this.tracker);
},
// 监听中
onTracked(event){
// 判断终止条件, stop是异步的,不返回的话,还会一直截图
if (this.count >= 21) {
this.onStopTracking();
return;
}

// 画框框
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
event.data.forEach(rect => {
this.context.lineWidth = 1;
this.context.strokeStyle = "#a64ceb";
//'#a64ceb';
this.context.strokeRect(rect.x, rect.y, rect.width, rect.height);
this.context.font = "11px Helvetica";
this.context.fillStyle = "#fff";
// 截图

if (event.data.length > 0 && this.count <= 20) {
if (this.count < 0) {
this.count = 0
}
this.count += 1
if (this.count > 20) {
this.isdetected = '已检测到人脸,正在识别'
this.getPhoto()
}
} else {
this.count -= 1
if (this.count < 0){
this.isdetected = '请您保持脸部在画面中央'
}
}


});
// 视频中心展示文字
this.context.fillText(this.isdetected, 100,30);
},
// 停止监听
onStopTracking() {
this.trackerTask.stop();
this.video.pause();
// 关闭摄像头
this.video.srcObject = null
window.stream.getTracks().forEach(track => track.stop())

},
// 获取人脸照片
getPhoto(){
this.isdetected = ''
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
let video = document.getElementById('video')
this.context.drawImage(video, 0,0, this.canvas.width, this.canvas.height)
let dataUrl = this.canvas.toDataURL('image/jpeg', 1);
this.imgbase64 = dataUrl.replace(/^data:image\/\w+;base64,/, "");
// 开始人脸识别
this.postFace()

},
// 初始化调用Token
getToken(){
this.$axios.post('http://192.168.50.35:3000/getToken',{}).then((res)=>{
this.access_token = res.data.access_token
})
},
// 人脸验证
postFace(){
this.loding = '正在识别中,请稍后................'
this.$axios.post('http://192.168.50.35:3000/checkFace',{
access_token: this.access_token,
img: this.imgbase64
}).then((res)=>{
console.log(res)
this.loding = ''
if(res.data.error_code !== 0){
if(res.data.error_code == 223120){
alert('活体监测失败')
}
}else {
if(res.data.result.user_list[0].score > 80){
alert('人脸识别成功')
}else{
alert('人脸识别失败,查不到')
}
}
})
},
// 视频流启动
getMediaStreamSuccess(stream) {
window.stream = stream
this.video.srcObject = stream
},
// 视频媒体流失败
getMediaStreamError(error) {
alert('视频媒体流获取错误' + error)
},
},
mounted() {
this.video = this.$refs.videoDom
this.canvas = this.$refs.canvasDOM

//初始化获取tonken
this.getToken();
},
destroyed() {

}
}
</script>

<style scoped>
.user-icon {
position: relative;
margin: 0 auto;
margin-top: 10px;
width: 360px;
height: 360px;
}
.button {
width: 90vw;
height: 50px;
line-height: 50px;
margin: 0 auto;
background-color: skyblue;
color: white;
text-align: center;
border-radius: 5px;
font-size: 16px;
}
video, canvas {
position: absolute;
}
</style>

完整的代码中包含了,人脸识别认证后自动截图,自动关闭摄像头等功能

示意图,如果有人脸,是会有紫色的框框,这里因为没有人脸,所以没有

需要注意的是,在移动端,由于安全策略的原因,摄像头不能开启成功,录音等audio自动播放因为安全策略也都是不可以的.

以上就是我对vue中实现人脸识别的一些理解,如果文章由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的博文,以避免误人子弟。

-------------本文结束感谢您的阅读-------------
没办法,总要恰饭的嘛~~