概述
目前市场上的人脸识别技术已经相对成熟,并且已经广泛的应用于门禁,考勤,美颜软件等方面。但是对于开发者来说自己开发高效准确的算法并不是一件容易的事情,因此很多公司提供了良好的API接口来让开发者能够将精力集中在软件的拓展功能实现上。Face++是北京旷视科技有限公司旗下的新型视觉服务平台,Face++平台通过提供云端API、离线SDK、以及面向用户的自主研发产品形式,将人脸识别技术广泛应用到互联网及移动应用场景中,非常重要的是它对于非商业用户提供免费试用帐号注册。将树莓派作为硬件载体,使用face++人脸识别云平台能够在宿舍中搭建一个性价比很高的门禁系统,通过这一过程能够更加深刻的理解嵌入式系统以及云服务的广泛应用,为使用其他的云服务API接口打下良好的基础。
Face++所有的API接口都是使用POST请求进行调用的,但是C++下的POST调用需要libcurl相关的库,并且要进行复杂的编译工作,代码量也非常大。因此使用python来完成相关的编程工作能够大大的简化代码以便于理解,并且树莓派也是支持python的编译器的。
准备工作
一、face++的注册与配置
首先登入face++的官方网站https://www.faceplusplus.com.cn/
点击右上角的注册按钮进入注册界面,按步骤完成注册信息填写并进行邮箱验证
在概览界面可以看到快速开始栏,点击“填写开发者资料”完善相关资料。之后按步骤进行API Key的创建,这是非常关键的一步。
其中类型一定要填写试用,只有创建试用API Key才能使用 API 免费服务,并且一个用户只能有一个免费API Key。免费服务是有一些限制的:
之后在应用管理-API Key界面就可以看到两个非常关键的参数,API Key和API Secret,在所有的POST调用当中均需要这两个参数。
二、安装python的OpenCV库
由于Python在window下的安装非常简单,故不再赘述。安装的版本会影响opencv库的安装。Opencv2.4.9只支持python2.7的版本,我这里使用的是2.7.11的版本。Opencv3则支持python3.0以上的版本。
首先解压Opencv并在…\opencv\opencv\build\python\2.7\x86目录下找到cv2.pyd
将cv2.pyd复制到python库目录下,路径如图所示,需要根据python2.7的安装路劲自行寻找。
此时还缺少一个numpy依赖包,这是Opencv库所需要的。在其官网http://sourceforge.net/projects/numpy/files/选择适合python2.7的安装包进行下载安装,如果你的python安装路径是默认的,只需要一直点下一步,如果不是默认路径需要设置自定义的安装路径。
这些工作完成之后在python IDE中输入:import cv2,如果没有报错,则python的Opencv库已经配置正确并可以使用了。
三、安装python 的requests库
requests是Python的一个HTTP客户端库,跟urllib,urllib2类似
下载地址:https://pypi.python.org/pypi/requests#downloads
将下载后的文件解压至python2.7根目录后,按win+R在运行中输入CMD启动命令行,切换至解压的文件目录下,运行python setup.py install进行安装。
之后在python IDE中输入:import requests,检验requests库是否配置成功
一、人脸识别模块
调用者提供图片文件或者图片URL,进行人脸检测和人脸分析。识别出的人脸会给出face_token,用于后续的人脸比对等操作。请注意,只对人脸包围盒面积最大的5个人脸进行分析,其他人脸可以使用Face Analyze API进行分析。如果您需要使用检测出的人脸于后续操作,建议将对应face_token添加到FaceSet中。如果一个face_token连续72小时没有存放在任意FaceSet中,则该face_token将会失效。如果对同一张图片进行多次人脸检测,同一个人脸得到的face_token是不同的。
调用URL:https://api-cn.faceplusplus.com/facepp/v3/detect
实现所需要的python代码:
#coding=utf8
import cv2
import requests
import json
url = 'https://api-cn.faceplusplus.com/facepp/v3/detect'
files = {'image_file':open('2.jpg', 'rb')}
payload = {'api_key': 'wRtmsh3Df9e6UnzKfoTQQl1YUwCrgIjG',
'api_secret': '04wlI86pykQAssFEAeVS0QTZgMb5gEW',
'return_landmark': 0,
'return_attributes':'gender,age,glass'}
r = requests.post(url,files=files,data=payload)
data=json.loads(r.text)
print r.text
width = data['faces'][0]['face_rectangle']['width']
top = data['faces'][0]['face_rectangle']['top']
height = data['faces'][0]['face_rectangle']['height']
left = data['faces'][0]['face_rectangle']['left']
img = cv2.imread("2.jpg")
vis = img.copy()
cv2.rectangle(vis, (left, top), (left+width, top+height),(0, 255, 0), 2)
cv2.imshow("Image", vis)
cv2.waitKey (0)
运行得到的结果:返回的JSON字符串:
经过格式化之后可以得到:
{
"image_id": "fr/Jyp4W2/9vg1dTeG6V+A==",
"request_id": "1483350389,e513b545-1ee2-40ff-b5de-46fe230c023c",
"time_used": 314,
"faces": [
{
"attributes": {
"gender": {
"value": "Male"
},
"age": {
"value": 20
},
"glass": {
"value": "Normal"
}
},
"face_rectangle": {
"width": 165,
"top": 149,
"left": 98,
"height": 165
},
"face_token": "aed9bd2e981bbcb0614af1d31e8be440"
}
]
}
根据返回的脸部矩形框的参数我们可以在原图片上绘制矩形框:
从上图系统还能够返回性别,大致年龄和是否戴眼镜等信息。其中上边比较重要的参数是face_token,这是后续进行人脸搜索比较的唯一标识。在上述的程序中有两个比较关键的地方:1.文件类型参数的传入必须是二进制文件,使用打开函数的参数是‘rb’2.返回的JSON字符串必须转换成python能够访问的字典列表套嵌结构,这样才能够正确的访问其中的参数。
二、人脸集合建立模块
创建一个人脸的集合FaceSet,用于存储人脸标识face_token。一个FaceSet能够存储1,000个face_token。
调用URL:https://api-cn.faceplusplus.com/facepp/v3/faceset/create
实现所需要的python代码:
#coding=utf8
import requests
url = 'https://api-cn.faceplusplus.com/facepp/v3/faceset/create'
payload = {'api_key': 'wRtmsh3Df9e6UnzKfoTQQl1YUwCrgIjG',
'api_secret': '04wlI86pykQAssFEAeVS0QTZgMb5gEW',
'display_name':'Dorm_1014',
'outer_id':'dorm',
'face_tokens':'c116a106c02f6ffd8606408fe2fb5def'
}
r = requests.post(url,data=payload)
print r.text
三、人脸搜索对比
在Faceset中找出与目标人脸最相似的一张或多张人脸。支持传入face_token或者直接传入图片进行人脸搜索。使用图片进行比对时会选取图片中检测到人脸尺寸最大的一个人脸。
调用URL:https://api-cn.faceplusplus.com/facepp/v3/search
实现所需要的python代码:
#coding=utf8
import cv2
import cv2.cv as cv
import requests
import json
capture = cv.CaptureFromCAM(0)
while True:
img = cv.QueryFrame(capture)
cv.ShowImage("camera",img)
key = cv.WaitKey(10)
if key == 27:
break
if key == ord(' '):
filename = "face.jpg"
cv.SaveImage(filename,img)
print "图片截取成功"
del(capture)
cv.DestroyWindow("camera")
url = 'https://api-cn.faceplusplus.com/facepp/v3/search'
payload = {'api_key': 'wRtmsh3Df9e6UnzKfoTQQl1YUwCrgIjG',
'api_secret': '04wlI86pykQAssFEAeVS0QTZgMb5gEW',
'faceset_token':'7d72d340e352716576921c806deb9dbb',
}
files = {'image_file':open('face.jpg', 'rb')}
r = requests.post(url,files=files,data=payload)
data=json.loads(r.text)
print r.text
if data["results"][0]["face_token"] == "cf12f3aef525a290f4035bb4e55aa94b" and data["results"][0]["confidence"]>=data["thresholds"]["1e-5"]:
print'\n东121014刘伟'
elif data["results"][0]["face_token"] == "c116a106c02f6ffd8606408fe2fb5def"and data["results"][0]["confidence"]>=data["thresholds"]["1e-5"]:
print'\n东121014葛炳为'
else:
print '\n不是我们宿舍的成员'
首先调用电脑摄像头获取视频图像,按空格键截图,成功会有提示。截图成功之后按ESC退出摄像头,将人脸图片上传至云端进行对比并返回结果。将其移植到嵌入式系统上就是用树莓派连接USB摄像头采集图像并在显示屏上显示,按键截取人脸上传云端比对返回结果,如果结果正确则打开电磁锁,结果不正确将会记录下开门者的面部信息记录。由于不能对宿舍门进行改造,机械结构和门锁装置目前不考虑实现。只实现识别功能。由于我在faceset:dorm121014中只放置了两个人脸作为实例,目前只能判定这两人属于该宿舍。
这是从摄像头截取到的人像:
API接口返回的数据:
这里已经正确的判断出我是属于这个宿舍的人。
如果换一个并不在faceset中的人重新进行验证,那么会有不同的结果。
重新从摄像头截取图像:
得到如下的返回:
关于如何进行人脸的对比,原理如下,在之前的人脸检测中我们得到了不同人脸的face_token并把他们放在了一个人脸集合中。在调用search API之后会返回一组JSON字符串,在格式话之后得到:
{
"image_id": "gaYm7xFYIIbKovs+/VzGPw==",
"faces": [
{
"face_rectangle": {
"width": 200,
"top": 252,
"left": 140,
"height": 200
},
"face_token": "37b00c249a6e606e86e923a4ea31be66"
}
],
"time_used": 511,
"thresholds": {
"1e-3": 65.3,
"1e-5": 76.5,
"1e-4": 71.8
},
"request_id": "1483353556,3819f817-f122-4448-8ed0-963dc47080f4",
"results": [
{
"confidence": 48.713,
"user_id": "",
"face_token": "c116a106c02f6ffd8606408fe2fb5def"
}
]
}
其中thresholds和face_token就是人脸检测需要的关键参数,返回的结果中会返回当前人脸的信息,以及在faceset中与之最相似的一张人脸的信息,以及相似的置信度和阈值。通过判断当前人脸的的face_token能够进行身份识别,之后在置信度大于十万分之一误识率的情况下才可以认定是属于该宿舍的成员。因为人与人或多或少总会有些相似,只有在满足置信度的条件下才能相对准确的判断。
虽然人脸识别在广义上并没有问题,但是如果应用于门禁上需要很高的安全系数。如果有人使用照片来开门的是很大的安全隐患。因此如何让系统明白到底站在它面前的是图片还是一个真实的人是至关重要的。考虑到硬件组件和实现的难度,这里只提出解决的方案。
1.face++的人脸识别能够识别人脸的姿态,因此在每次验证之前告诉开门者做出随机的头部姿态的调节方式,并根据返回的姿态参数进行验证,但姿态参数和上述验证都满足的情况下才能认定身份的有效性。但是很多情况下由于光线或者开门者的动作达不到要求而导致一定的误判。
2.使用双目摄像头经过处理之后获得景深信息,照片和真人的景深信息有着明显的差异,能够相对准确的判断出在系统前的到底是真人还是图片。但该方式要增加比较大的成本。
[1]旷视API文档https://console.faceplusplus.com.cn/service/face/intro
[2]python菜鸟教程http://www.runoob.com/python/python-tutorial.html
[3]requests快速上手http://docs.python-requests.org/zh_CN/latest/user/quickstart.html
[4]c++中face++API的调用http://blog.csdn.net/hei_ya/article/details/51648999
[5]使用 OpenCV与Face++实现人脸解锁http://python.jobbole.com/84666/
[6]使用Python解析JSON数据的基本方法http://www.jb51.net/article/73450.htm