百度AI实现人脸识别之人脸检测(Qt版)

版权声明:最终版权归YBAidam所有 https://blog.csdn.net/Aidam_Bo/article/details/85126688

前言


本文主要实现打开一张人脸图片,识别出年龄、性别、颜值等人脸属性信息。其它的人脸比对、身份验证、活体检测等等功能都可以在此基础上进行扩展,以及对人脸识别接口的调用和信息处理。

Demo运行结果


这个功能可以当做是娱乐功能,同一个人不同风格的照片识别结果可能不同。


百度AI人脸识别接入


为什么使用百度AI接口


人脸识别可接入的平台挺多的,阿里云、腾讯云、Face++等等,如果是商用的话就得慎重了,毕竟要考虑的不仅是接口稳定性,还有价格、技术支持、售后等很多方面。这里只是用来学习,所以考虑的问题就比较简单了,只是关乎Money,而百度AI的接口绝大部分都免费,只是商用需要高并发或者一些付费资源的话需要付费,学习的话免费资源完全满足需求了。同样注册了阿里云的应用,直接收费,Face++给了限定的测试次数,所以选择了百度AI。技术而言,Face++可能在人脸识别这方面更专业一点,但目前各大平台的识别率基本没有什么区别。

è¿éåå¾çæè¿°


接入步骤

  1. 注册百度账号,用来登录百度AI开发平台(http://ai.baidu.com/),有账号的可以直接登录
  2. 注册成为开发者
  3. 创建应用,应用创建成功之后也就开通了人脸检测、人脸比对等等相关业务
  4. 获取密钥,AppID、API Key和Secret key
  5. 生成签名(Access Token),这个写代码的时候要用到,每个应用的Access Token有效期为30天,到期后要重新获取,或者是在写代码时每次都获取一下
  6. 启动开发

百度AI开放平台上有详细的接入指南:http://ai.baidu.com/docs#/Begin/top

如何获取Access Token


向授权服务地址https://aip.baidubce.com/oauth/2.0/token发送请求(推荐使用POST),并在URL中带上以下参数:

  • grant_type: 必须参数,固定为client_credentials
  • client_id: 必须参数,应用的API Key
  • client_secret: 必须参数,应用的Secret Key

具体的参数值可以在下图位置中的“应用列表”里查看:

è¿éåå¾çæè¿°

使用在线post工具按照上面的地址和参数进行请求就可以得到Access Token了,百度搜索“在线post工具"有很多可用的,这里使用http://coolaf.com/举例:

è¿éåå¾çæè¿°



Qt软件开发


编程部分并不复杂,主要是对百度AI接口的调用及对请求数据的解析。但实现示例的功能还是用到了挺多知识点,下面会进行记录。

人脸检测Qt编程步骤

  1. 绑定请求服务器地址和密钥
  2. 按照百度人脸检测接口的格式要求添加header
  3. 将要检测的图片转换为为BASE64编码(这里需要注意一下,官方说上传的图片不能大于2M,测试了一个3M的图片依然可以请求成功,不过需要好几秒才能收到反馈,测试的3M的图片转成BASE64编码后长度超过1000万个字节,图片越小识别的速度越快)
  4. 按照百度人脸检测接口的格式要求打包body数据
  5. 使用post方式上传请求
  6. 解析反馈数据

注意:这里的请求内容必须按照百度接口指定的格式,格式如下


知识点


网络编程


这里使用了QtNetwork模块中的网络接口来实现http编程,需要在.pro文件中添加 QT += network,主要用到了下面三个类:

  • QNetworkAccessManager:该类允许应用程序发送网络请求和接收回复,类似于一个中转站或者一个容器,每当有请求创建或者接收到回复都由该类进行调度
  • QNetworkRequest:网络请求
  • QNetworkReply:网络请求的应答,在请求被完成调度是由QNetworkAccessManager创建

get、put、post请求方式的区别简述


这里只用到了post请求,并且目前大多数网络请求的方式均使用post。

  • GET请求(类似于数据库select操作),会向数据库发送数据的请求,从而来获取信息,不会改变数据内容,并且无论进行多少次操作,结果都是一样的
  • PUT请求(类似于数据库update操作),是会向服务器端发送数据的,会修改数据的内容,但是不会增加数据的种类,并且无论进行多少次操作,结果都是一样的
  • POST请求(类似于数据库insert操作),是会向服务器端发送数据的,但是该请求会改变数据的种类等资源,会创建新的内容

POST 提交数据方式


常用格式如下:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • application/json
  • text/xml

这篇文章里有这四种方式的详细介绍

如何对图片进行BASE64编码

  1. 提取图片
  2. 数据转换为BASE64编码

代码如下:

QImage image("H:/test.jpg");
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
//以png格式将图片数据写入ba
image.save(&buffer, "png");
//将图片进行BASE64编码
QString imgData = QString(ba.toBase64());
buffer.close();


JSON数据解析


这部分内容还挺多的,可以从网络学习JSON教程,下面的代码里也有用到。

核心代码


数据上传

//设置请求地址
QUrl url(requestUrl + "?access_token=" + accessToken);
QNetworkRequest request(url);

//设置数据提交格式,这个不能自己随便写,每个平台的格式可能不一样,百度AI要求的格式为application/json
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

//将要检测的图片进行BASE64编码
QImage image(imgPath);
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
//以png格式将图片数据写入ba
image.save(&buffer, "png");
//将图片进行BASE64编码
QString imgData = QString(ba.toBase64());
buffer.close();

//打包请求参数
QJsonObject post_data;;
QJsonDocument document;
post_data.insert("image", imgData);
post_data.insert("image_type", "BASE64");
post_data.insert("face_field", "age,beauty,gender,expression");
document.setObject(post_data);
QByteArray post_param = document.toJson(QJsonDocument::Compact);

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


请求反馈数据解析

replyData = reply->readAll();
qDebug()<<"reply data is:"<<QString(replyData);

QJsonParseError json_error;
QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
if(json_error.error == QJsonParseError::NoError)
{
    //判断是否是对象,然后开始解析数据
    if(document.isObject())
    {
        QJsonObject obj = document.object();
        //解析反馈的人脸属性结果
        if(obj.contains("result"))
        {
            QJsonObject resultObj = obj.take("result").toObject();
            //解析人脸个数
            if(resultObj.contains("face_num"))
            {
                int faceNum = obj.take("face_num").toInt();
                qDebug()<<"查询到了图片中的人脸个数为:"<<faceNum;
            }
            //解析人脸属性
            if(resultObj.contains("face_list"))
            {
                QJsonArray faceArray = resultObj.take("face_list").toArray();

                for(int i = 0; i < faceArray.size(); i++)
                {
                    QJsonObject faceObj = faceArray.at(i).toObject();
                    if(faceObj.contains("gender"))
                    {
                        QJsonObject genderObj = faceObj.take("gender").toObject();
                        if(genderObj.contains("type"))
                        {
                            QString type = genderObj.take("type").toString();;
                            if(type == "male")
                            {
                                ui->lblSex->setText("男");
                            }
                            else
                            {
                                ui->lblSex->setText("女");
                            }
                        }
                    }
                    if(faceObj.contains("age"))
                    {
                        int age = faceObj.take("age").toDouble();
                        qDebug()<<"查询到了年龄:"<<age;
                        ui->lblAge->setText(QString::number(age));
                    }
                    if(faceObj.contains("beauty"))
                    {
                        int beauty = faceObj.take("beauty").toDouble();;
                        qDebug()<<"查询到了颜值:"<<beauty;
                        ui->lblBeauty->setText(QString::number(beauty));
                    }
                    if(faceObj.contains("expression"))
                    {
                        QJsonObject expressionObj = faceObj.take("expression").toObject();
                        if(expressionObj.contains("type"))
                        {
                            QString type = expressionObj.take("type").toString();;
                            if(type == "smile")
                            {
                                ui->lblFeature->setText("微笑");
                            }
                            else if(type == "laugh")
                            {
                                ui->lblFeature->setText("大笑");
                            }
                            else
                            {
                                ui->lblFeature->setText("不笑");
                            }
                        }
                    }
                }
            }
        }
    }
}
reply->deleteLater();



完整示例代码
https://download.csdn.net/download/aidam_bo/10864949

猜你喜欢

转载自blog.csdn.net/Aidam_Bo/article/details/85126688