近几年,生物特征识别技术获得快速发展。人脸作为一种生物特征,具有很强的自身稳定性和个体差异性,是进行身份验证的最理想依据,主要方法包括步态识别、虹膜识别、皮肤芯片、脸像识别、多模态(即多生物特征融合)技术等。其中,人脸识别技术因为具有方便、直观、易于普及等优点尤为受到关注与研究。
文章针对当前常用考勤方式中普遍存在的代签到、考勤数据整合较慢等问题,利用华为云的人脸识别技术实现了一种基于QT框架设计的在线考勤系统。该系统可大大提高考勤效率,满足各类场环境景下的考勤需求,具有识别度高、检测速度快、操作简单的特点,能够为用户提供更多便利帮助。
实现大致流程:
核心思路总结:
华为云人脸识别服务支持,人脸库创建,向人脸库添加人脸,在人脸库里搜索匹配的人脸,.......很多功能。当前
考勤系统主要用到这3个功能。
创建人脸库: 在创建人脸库的时候,支持创建自定义字段,也就是每个人脸可以加一些自定义的属性描述,但是不支持中文字符,如果是字符串字段,范围是0~255长度;
向人脸库添加人脸: 如果在创建人脸库的时候,注册了自定义字段,在添加人脸的时候就可以带上自定义字段的描述,除了添加自定义字段,也可以添加ID,这个ID关联数据库方便考勤的时候进行查找对比。
在人脸库搜索人脸: 可以取一张本地的图片与人脸库里存在的人脸进行匹配,得到相识度,在搜索人脸的时候也可以设置过滤条件,常见的条件就是相识度阀值,低于设置阀值就不返回,也可以设置自定义字段返回,如果注册人脸的时候添加了自定义属性,在识别到人脸的时候就可以通过返回的自定义属性判断这个人脸是谁。
考勤实现核心思路:
向人脸库添加人脸的时候,可以指定external_image_id
字段,这个是代表图片外部ID,与当前图像绑定,这个字段可以存放在本地的数据库里,在考勤的时候,从当前摄像头取一帧图像与华为云人脸库里的图像进行对比,找到相识度最高的一张图片,然后这张图片的external_image_id
字段,然后与数据库里的external_image_id
字段匹配,就找到这个人的详细信息了(详细信息是存放到本地数据库里的),然后就可以实现考勤逻辑了。
软件最终的效果:
(1)主界面
(2)打开摄像头
如果视频里没有人脸,会有错误提示的。
(3)点击人脸注册,添加工号自定义属性
(4)点击人脸搜索:搜索到之后会把自定义的属性显示出来--工号
其他功能都不在演示了,详细实现看下面章节的代码流程。
项目源码下载地址: https://download.csdn.net/download/xiaolong1126626497/71245801
官网地址: https://console.huaweicloud.com/frs/?region=cn-north-4&locale=zh-cn#/frs/manage/index
如果没有华为云账号,打开上面地址时,需要先注册,如果有账号登录之后就可以看到下面的页面,鼠标移到最右边,开通对应的服务。
官方帮助文档地址: https://support.huaweicloud.com/api-face/face_02_0088.html
在使用API访问接口时,需要填充很多的参数,endpoint
,project_id
等等。
关于这些API需要使用的签名参数介绍在这个页面里:https://support.huaweicloud.com/devg-apisign/api-sign-provide-start.html
Endpoint 是代表地区与终端节点,即云服务在不同Region有不同的访问域名。
查看地址: https://developer.huaweicloud.com/endpoint
打开链接之后,选择自己的服务,然后往下翻就可以看到对应服务的地址。
华北-北京四 cn-north-4 face.cn-north-4.myhuaweicloud.com HTTPS
获取AK/SK
在API凭证页面可以看到项目ID:
华为云提供了在调试API接口,非常方便,可以提前验证功能是否正常。
地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=FRS&api=CreateFaceSet
选择自己要调试的API,然后填充对应的参考,进行调试即可。
下面的例子是创建人脸库。
如果同一个人脸库创建两次,就会报错,可以在调试页面看到错误的提示,方便自己写代码时进行判断,处理。
如果不清楚访问的域名地址是多少,在调试接口页面是可以直接获取查看的。
创建人脸库的时候,还可以指定自定义字段,方便对这张人脸进行打个性化标签属性,方便知道这张脸是谁的。
请求头:
{
"User-Agent": "API Explorer",
"X-Auth-Token": "******",
"Content-Type": "application/json"
}
请求体:
{
"external_fields": {
"face_name": {
"type": "string"
},
"face_phone": {
"type": "string"
},
"face_class": {
"type": "string"
}
},
"face_set_name": "face3"
}
/*
功能: 创建人脸库
*/
void Widget::HuaweiCreatesFaceDatabase(QString face_lib_name)
{
//表示创建人脸库
function_select=2;
QString requestUrl;
QNetworkRequest request;
//设置请求地址
QUrl url;
//人脸注册的请求地址
requestUrl = QString("https://face.%1.myhuaweicloud.com/v2/%2/face-sets")
.arg(SERVER_ID)
.arg(PROJECT_ID);
//自己创建的TCP服务器,测试用
//requestUrl="http://10.0.0.6:8080";
//设置数据提交格式
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
//设置token
request.setRawHeader("X-Auth-Token",Token);
//构造请求
url.setUrl(requestUrl);
request.setUrl(url);
//添加自定义字段 external_fields这个对象就是自定义字段
//我这里只是定义了3个字段,可以自己增加
//添加人脸的时候也需要添加这里设置的自定义字段
QString post_param=QString("{"
""external_fields": {"
""face_name": {"
""type": "string""
"},"
""face_phone": {"
""type": "string""
"},"
""face_class": {"
""type": "string""
"}"
"},"
""face_set_name": "%1""
"}").arg(face_lib_name);
//发送请求
manager- >post(request, post_param.toUtf8());
}
使用API访问华为云的所有服务接口,都需要填X-Subject-Token参数,下面介绍步骤:
鼠标悬停在右上角的用户名称上,弹出下拉框,选择统一身份认证。
右边响应头里的X-Subject-Token
就是获取的token。
获取X-Subject-Token请求的地址: https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens
请求头数据:
{
"User-Agent": "API Explorer",
"X-Auth-Token": "******",
"Content-Type": "application/json;charset=UTF-8"
}
请求体数据:
{
"auth": {
"identity": {
"methods": [
"password"
],
"password": {
"user": {
"domain": {
"name": "xxxxx" //这里填当前主账户名称
},
"name": "xxxx", //这个新建的子账户名称
"password": "xxxxx" //这个是新建的子账户密码
}
}
},
"scope": {
"project": {
"name": "cn-north-4"
}
}
}
}
/*
功能: 获取token
*/
void Widget::GetToken()
{
//表示获取token
function_select=3;
QString requestUrl;
QNetworkRequest request;
//设置请求地址
QUrl url;
//获取token请求地址
requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
.arg(SERVER_ID);
//自己创建的TCP服务器,测试用
//requestUrl="http://10.0.0.6:8080";
//设置数据提交格式
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));
//构造请求
url.setUrl(requestUrl);
request.setUrl(url);
QString text =QString("{"auth":{"identity":{"methods":["password"],"password":"
"{"user":{"domain": {"
""name":"%1"},"name": "%2","password": "%3"}}},"
""scope":{"project":{"name":"%4"}}}}")
.arg(MAIN_USER)
.arg(IAM_USER)
.arg(IAM_PASSWORD)
.arg(SERVER_ID);
//发送请求
manager- >post(request, text.toUtf8());
}
官方地址: https://support.huaweicloud.com/api-face/face_02_0093.html
添加人脸调试接口地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=FRS&api=AddFacesByFile
请求地址: https://face.cn-north-4.myhuaweicloud.com/v2/项目ID/face-sets/人脸库名称/faces
请求方式: post
请求头:
{
"User-Agent": "API Explorer",
"X-Auth-Token": "******", //替换成自己的token
"Content-Type": "application/json"
}
请求体:
{
"image_base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAk..........."
}
文档地址: https://support.huaweicloud.com/api-face/face_02_0094.html
调试地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=FRS&api=ShowFaceSet
//注册人脸,添加人脸,添加自定义数据
//QString name 这个是自定义字段,0~255 字节,只能英文字母和数字
void Widget::RegFace2(const QImage image,QString face_lib,QString name)
{
function_select=0;
QString requestUrl;
QNetworkRequest request;
//存放图片BASE64编码
QString imgData;
//设置请求地址
QUrl url;
//人脸注册的请求地址
requestUrl = QString("https://face.%1.myhuaweicloud.com/v2/%2/face-sets/%3/faces")
.arg(SERVER_ID)
.arg(PROJECT_ID)
.arg(face_lib);
qDebug()< < "requestUrl:"<
官方文档地址: https://support.huaweicloud.com/api-face/face_02_0086.html
接口地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=FRS&api=SearchFaceByFile
我这里调试接口里选择本地指定文件与人脸库的人脸进行匹配,返回相识度。
返回的结果:
{
"faces": [
{
"face_id": "6ED4NSsS",
"external_image_id": "FPhviHgr",
"bounding_box": {
"width": 197,
"top_left_x": 201,
"top_left_y": 80,
"height": 241
},
"similarity": 1
},
{
"face_id": "EpBvdmp5",
"external_image_id": "ubxcVUpN",
"bounding_box": {
"width": 104,
"top_left_x": 111,
"top_left_y": 100,
"height": 123
},
"similarity": 0.9802261
},
{
"face_id": "cSKntQmF",
"external_image_id": "nBoRpVab",
"bounding_box": {
"width": 113,
"top_left_x": 65,
"top_left_y": 106,
"height": 127
},
"similarity": 0.97810614
},
{
"face_id": "TZGv2cKI",
"external_image_id": "49y0pLG9",
"bounding_box": {
"width": 104,
"top_left_x": 90,
"top_left_y": 97,
"height": 125
},
"similarity": 0.9768342
},
{
"face_id": "3p1Ho8Vw",
"external_image_id": "vpuYDUvU",
"bounding_box": {
"width": 108,
"top_left_x": 100,
"top_left_y": 108,
"height": 122
},
"similarity": 0.9619592
},
{
"face_id": "nIuMJ1fA",
"external_image_id": "v8mNyJSY",
"bounding_box": {
"width": 102,
"top_left_x": 58,
"top_left_y": 141,
"height": 98
},
"similarity": 0.95380914
},
{
"face_id": "IamCTWR9",
"external_image_id": "KzUyJDxU",
"bounding_box": {
"width": 108,
"top_left_x": 32,
"top_left_y": 142,
"height": 97
},
"similarity": 0.5663861
}
]
}