调用百度人脸AI接口实现人脸识别(深层次算法属于BaiduAI,研究整个流程还是花了一些时间,毕竟是新东西)
首先我们先从获取摄像头中的人脸开始
调用摄像头
一开始我在想一下子就想到的方法,openvc来调用摄像头获取人脸照片
但是这是针对网页应用,如果能通过前端获取带有人脸的照片不更好吗?把负载加到用户浏览器处
所以就有了下面的js代码
$(document).ready(function () {
var video = document.getElementById('video'),
canvas = document.getElementById('canvas'),
regButton = document.getElementById('regButton'),
student_id = document.getElementById('student'),
vendorUrl = window.URL || window.webkitURL;
//媒体对象
// 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
// 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
// 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
// 首先,如果有getUserMedia的话,就获得它
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
// 否则,为老的navigator.getUserMedia方法包裹一个Promise
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
}
}
navigator.mediaDevices.getUserMedia({ audio: false, video: { 'facingMode': "user" } })
.then(function (stream) {
var video = document.querySelector('video');
// 旧的浏览器可能没有srcObject
if ("srcObject" in video) {
video.srcObject = stream;
} else {
// 防止在新的浏览器里使用它,因为它已经不再支持了
video.src = window.URL.createObjectURL(stream);
}
video.onloadedmetadata = function (e) {
video.play();
};
})
.catch(function (err) {
console.log(err.name + ": " + err.message);
});
regButton.addEventListener('click', function () {
//绘制canvas图形
canvas.getContext('2d').drawImage(video, 0, 0, 400, 300);
//把canvas图像转为img图片
var data = {
img: canvas.toDataURL("image/png"),
student_id: student_id.value
}
$.ajax(
{
type: 'POST',
url: '../checkReg',
data: JSON.stringify(data),
dataType: "json",
complete: function(res){
console.log(res);
if (res.responseJSON) {
alert(res.responseJSON.msg);
}
else {
alert("服务端发生错误")
}
}
}
)
});
})
这里我们使用navigator来调用摄像头设备并通过canvas将video对象绘制成图片
再通过post传给后端就行了,这里采用了base64的方式
同时百度接口也只接受base64格式的图片,至此获取图片步掫我们已经完成了
后端调用百度AI接口
后端接收到图像之后,经过一些必要的过滤措施
就可以向百度接口post数据了,但是我们首先要注意的就是把前端的图像处理一下data,base64数据需要删除","之后的数据
base64.b64decode(image.split(',')[-1])
其他的我们都直接放置到config文件中,方便维护和调用,具体代码如下
client = current_app.config['CLIENT']
image = base64.b64decode(image.split(',')[-1])
det_options = current_app.config['DETOPTIONS']
check_image = client.detect(image, det_options)
if check_image['result'][0]['face_probability'] != 1:
return jsonify({"status": False, 'msg': "请对准人脸"})
groupId = current_app.config['GROUP_ID']
add_options = current_app.config['ADDOPTIONS']
userInfo = ''
result = client.addUser(result_id, userInfo,
groupId, image, add_options)
if 'error_code' in result:
return jsonify({"status": False, 'msg': "请检查是否对准了摄像头"})
check_stu_num.log_id = result['log_id']
if check_stu_num.log_id:
return jsonify({"status": True, 'msg': "人脸更新成功"})
else:
return jsonify({"status": True, 'msg': "注册成功"})
其实我们需求很简单,就是在图片中对比人脸库里的人脸识别出来他是谁,使用百度AI有点大材小用的感觉
我们可以自己使用opencv的相关第三方库来实现的,也可以是使用一些简单的机器学习算法来实现
(懒字当头,当然使用这两个的前提是你要去先熟悉一下他们~)
关于IP的确定
这里采用了nginx记录x-header-ip数据来实现真实IP检测
在nginx配置里set一个X-Real-Ip,后端就可以使用request.header['X-Real-Ip']来获取IP地址了
一些基础的IP伪造还是可以过滤掉的
关于签到和签出
这里是通过判断用户的sign_status字段值和目前签到距离上次签到的时间来判断是否上次签出了和这次是否是签出动作
关键代码如下:
```python
if user.sign_statue and now_time-user.signlogs[-1].signtime < timedelta(days=1):
user.sign_statue = False
return jsonify({"status": True, 'msg': user.name+"
您签出成功了~"})
elif not user.sign_statue:
user.sign_statue = True
return jsonify({"status": True, 'msg': user.name+"
您签到成功了~
记得签出!!!!!!!!!"})
else:
user.sign_statue = True
return jsonify({"status": False, 'msg': user.name+"
您上次值班没有签出~
就先放过你,下次别忘了哦~
签到成功~"})
```
关于记录下载
就是一个对数据库查询和对xls文件写入的操作
然后为了办公方便,读取传入的指定days来确定要下载的天数
然后为了省事,也就是办公只需要签到历史,就采用了文件直接下载的形式
抛却了后台,只是构造密码形式的路由就行了
相似的,用户的录入也是同理只是对xls的读取操作罢了~
for user in users:
for user_signlog in user.signlogs:
now_time = datetime.now()
if not now_time-user_signlog.signtime < timedelta(hours=20*int(days)):
continue
...
data.save(current_app.config['SIGN_LOGS_CONTENS']+r'/result.xls')
return send_from_directory(current_app.config['SIGN_LOGS_CONTENS'], 'result.xls')
前端页面的实现
刚才已经说了一个摄像头的调用
当然也会在前端实时显示摄像头以便用户拍照操作
然后也是采用了类似微信登陆页面的样式(或许是为了懒省事)
中间的盒子模型,定义一下各种元素的位置和大小(后期维护可以根据需要调整)
还有就是签到点击按钮会有一段时间的延迟
这个动作我正在添加loading界面
以防用户不断的点击button按钮,来催促网页有回显
PS:数据库的建立是一对多的形式形式