1. 项目介绍

近几年,生物特征识别技术获得快速发展。人脸作为一种生物特征,具有很强的自身稳定性和个体差异性,是进行身份验证的最理想依据,主要方法包括步态识别、虹膜识别、皮肤芯片、脸像识别、多模态(即多生物特征融合)技术等。其中,人脸识别技术因为具有方便、直观、易于普及等优点尤为受到关注与研究。

文章针对当前常用考勤方式中普遍存在的代签到、考勤数据整合较慢等问题,利用华为云的人脸识别技术实现了一种基于QT框架设计的在线考勤系统。该系统可大大提高考勤效率,满足各类场环境景下的考勤需求,具有识别度高、检测速度快、操作简单的特点,能够为用户提供更多便利帮助。

实现大致流程:

  1. 注册华为云账号
  2. 开通华为云的人脸识别服务
  3. 通过API创建人脸库
  4. 将需要考勤识别的人脸,添加到人脸库
  5. 考勤时,调用本地摄像头获取人脸图像,与人脸库里注册的人脸进行对比,找到考勤人,完成考勤。

核心思路总结:

华为云人脸识别服务支持,人脸库创建,向人脸库添加人脸,在人脸库里搜索匹配的人脸,.......很多功能。当前

考勤系统主要用到这3个功能。

创建人脸库: 在创建人脸库的时候,支持创建自定义字段,也就是每个人脸可以加一些自定义的属性描述,但是不支持中文字符,如果是字符串字段,范围是0~255长度;

向人脸库添加人脸: 如果在创建人脸库的时候,注册了自定义字段,在添加人脸的时候就可以带上自定义字段的描述,除了添加自定义字段,也可以添加ID,这个ID关联数据库方便考勤的时候进行查找对比。

在人脸库搜索人脸: 可以取一张本地的图片与人脸库里存在的人脸进行匹配,得到相识度,在搜索人脸的时候也可以设置过滤条件,常见的条件就是相识度阀值,低于设置阀值就不返回,也可以设置自定义字段返回,如果注册人脸的时候添加了自定义属性,在识别到人脸的时候就可以通过返回的自定义属性判断这个人脸是谁。

考勤实现核心思路:

向人脸库添加人脸的时候,可以指定external_image_id字段,这个是代表图片外部ID,与当前图像绑定,这个字段可以存放在本地的数据库里,在考勤的时候,从当前摄像头取一帧图像与华为云人脸库里的图像进行对比,找到相识度最高的一张图片,然后这张图片的external_image_id字段,然后与数据库里的external_image_id字段匹配,就找到这个人的详细信息了(详细信息是存放到本地数据库里的),然后就可以实现考勤逻辑了。

软件最终的效果:

(1)主界面

image-20211221103909085

(2)打开摄像头

image-20211221104539725

如果视频里没有人脸,会有错误提示的。

image-20211221104641098

(3)点击人脸注册,添加工号自定义属性

image-20211226124307918

(4)点击人脸搜索:搜索到之后会把自定义的属性显示出来--工号

image-20211226124320572

image-20211226132557419

image-20211226132607167

image-20211226132618369

其他功能都不在演示了,详细实现看下面章节的代码流程。

项目源码下载地址: https://download.csdn.net/download/xiaolong1126626497/71245801

2. 创建人脸库

2.1 开通人脸识别服务

官网地址: https://console.huaweicloud.com/frs/?region=cn-north-4&locale=zh-cn#/frs/manage/index

如果没有华为云账号,打开上面地址时,需要先注册,如果有账号登录之后就可以看到下面的页面,鼠标移到最右边,开通对应的服务。

image-20211220102416288

2.2 创建人脸库

官方帮助文档地址: https://support.huaweicloud.com/api-face/face_02_0088.html

image-20211220102931041

image-20211220103034937

image-20211220103311203

2.3 AK/SK、ID、域名参数获取

在使用API访问接口时,需要填充很多的参数,endpointproject_id 等等。

关于这些API需要使用的签名参数介绍在这个页面里:https://support.huaweicloud.com/devg-apisign/api-sign-provide-start.html

image-20211220103455186

Endpoint 是代表地区与终端节点,即云服务在不同Region有不同的访问域名。

查看地址: https://developer.huaweicloud.com/endpoint

打开链接之后,选择自己的服务,然后往下翻就可以看到对应服务的地址。

image-20211220115558573

image-20211220115630617

华北-北京四	cn-north-4	face.cn-north-4.myhuaweicloud.com	HTTPS

获取AK/SK

  1. 打开控制台页面

  2. 将鼠标移至用户名,在下拉列表中单击“我的凭证”。

  3. 单击“访问密钥”。

  4. 单击“新增访问密钥”,进入“新增访问密钥”页面。

  5. 输入描述信息,单击“确定”,下载密钥,请妥善保管。

image-20211220104004923

image-20211220104041253

在API凭证页面可以看到项目ID:

image-20211220104734001

image-20211220104205132

image-20211220104224862

image-20211220104309722

2.4 在线调试接口

华为云提供了在调试API接口,非常方便,可以提前验证功能是否正常。

地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=FRS&api=CreateFaceSet

选择自己要调试的API,然后填充对应的参考,进行调试即可。

下面的例子是创建人脸库。

image-20211220115159426

如果同一个人脸库创建两次,就会报错,可以在调试页面看到错误的提示,方便自己写代码时进行判断,处理。

image-20211220115403185

如果不清楚访问的域名地址是多少,在调试接口页面是可以直接获取查看的。

创建人脸库的时候,还可以指定自定义字段,方便对这张人脸进行打个性化标签属性,方便知道这张脸是谁的。

image-20211220233435788

请求头:
{
 "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"
}

2.5 代码实现

/*
功能: 创建人脸库
*/
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());
}

3. 如何获取X-Subject-Token

使用API访问华为云的所有服务接口,都需要填X-Subject-Token参数,下面介绍步骤:

3.1 创建一个新的IAM帐户

鼠标悬停在右上角的用户名称上,弹出下拉框,选择统一身份认证。

image-20211220152929854

3.2 选择创建用户

image-20211220153051946

image-20211220153226036

image-20211220153255718

image-20211220153311429

3.3 使用调试接口测试获取oken

调试接口地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IAM&api=KeystoneCreateUserTokenByPassword

image-20211220153749278

右边响应头里的X-Subject-Token就是获取的token。

image-20211220154523194

3.4 上面的这些账户名称从哪里获取?

image-20211220153950194

image-20211220154123357

3.5 请求地址和数据格式

**获取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"
      }
    }
  }
}

3.5 代码实现

/*
功能: 获取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());
}

4. 向人脸库添加人脸

4.1 调试接口

官方地址: https://support.huaweicloud.com/api-face/face_02_0093.html

image-20211220183218596

image-20211220183415166

添加人脸调试接口地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=FRS&api=AddFacesByFile

image-20211220183713964

4.2 请求接口与地址总结

请求地址: 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..........."
}

4.3 查询人脸

文档地址: https://support.huaweicloud.com/api-face/face_02_0094.html

image-20211220223342018

调试地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=FRS&api=ShowFaceSet

image-20211220223528491

4.4 代码实现: 添加人脸时增加自定义字段

//注册人脸,添加人脸,添加自定义数据
//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:"<<requestUrl;
   // requestUrl="http://192.168.1.100:8080";
    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //将图片进行Base64编码
    imgData = QString(toBase64(image)); //编码后的图片大小不超过2M
    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);
    request.setUrl(url);

   QString post_param=QString
              ("{"
                "\"image_base64\": \"%1\","
                "\"external_fields\":{\"face_name\":\"%2\"},"
                "\"single\": true"
               "}").arg(imgData).arg(name);

    //发送请求
    manager->post(request, post_param.toUtf8());
}

5. 从人脸库搜索匹配的人脸

5.1 参数介绍

官方文档地址: https://support.huaweicloud.com/api-face/face_02_0086.html

image-20211221090644392

image-20211221093155305

5.2 调试接口

接口地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/doc?product=FRS&api=SearchFaceByFile

image-20211221090708217

我这里调试接口里选择本地指定文件与人脸库的人脸进行匹配,返回相识度。

image-20211221091619216

返回的结果:

{
 "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
  }
 ]
}

5.3 接口总结

这是总结的bas64编码的接口,方便编写代码进行搜索人脸。

请求地址: https://face.cn-north-4.myhuaweicloud.com/v2/项目ID/face-sets/人脸库名称/search
请求方式: POST
请求头:
{
 "User-Agent": "API Explorer",
 "X-Auth-Token": "******",    自己的token
 "Content-Type": "application/json"
}
请求体:
{
 "image_base64": "..........................................."   图片BAS64编码后的数据
}

5.4 代码实现

//人脸搜索功能
// threshold参数表示人脸相似度阈值,低于这个阈值则不返回,取值范围0~1,一般情况下建议取值0.93,默认为0。
void Widget::FindFace(const QImage image,QString face_lib,double threshold)
{
    function_select=1;
    QString requestUrl;
    QNetworkRequest request;

    //存放图片BASE64编码
    QString imgData;

    //设置请求地址
    QUrl url;

    //人脸搜索请求地址
    requestUrl = QString("https://face.%1.myhuaweicloud.com/v2/%2/face-sets/%3/search")
            .arg(SERVER_ID)
            .arg(PROJECT_ID)
            .arg(face_lib);

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //将图片进行Base64编码
    imgData = QString(toBase64(image)); //编码后的图片大小不超过2M
    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);
    request.setUrl(url);

    QString post_param=QString
               ("{"
                 "\"image_base64\": \"%1\","
                 "\"return_fields\":[\"face_name\"],"   //需要返回的自定义字段
                "\"threshold\":%2"
                "}").arg(imgData).arg(threshold);


    //发送请求
    manager->post(request, post_param.toUtf8());
}

6. 删除人脸库

文档地址: https://support.huaweicloud.com/api-face/face_02_0091.html

调试地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=FRS&api=DeleteFaceSet

image-20211221113900132

总结:

请求接口: https://face.cn-north-4.myhuaweicloud.com/v2/项目ID/face-sets/人脸库名称