基于Qt调用百度AI库进行人脸检测的测试代码

根据B站@井上远子_的“基于Qt的图像识别项目”写的测试代码。该代码为连续检测,但后来新申请的百度智能云账号赠送的调用次数有限制,连续检测可能很短的时间内就把一个月的赠送量用完了,建议可以修改为非连续调用,比如使用UI上的按钮单次触发。

1、UI

2、imageTest.pro

QT       += core gui multimedia multimediawidgets network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    imagetest.cpp \
    worker.cpp

HEADERS += \
    imagetest.h \
    worker.h

FORMS += \
    imagetest.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

3、imagetest.h

#ifndef IMAGETEST_H
#define IMAGETEST_H

#include <QWidget>

#include <QCamera>
#include <QCameraViewfinder>
#include <QCameraImageCapture>
#include <QTimer>
#include <QNetworkAccessManager>
#include <QUrl>
#include <QUrlQuery>
#include <QSslConfiguration>
#include <QNetworkReply>
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonObject>
#include <QBuffer>
#include <QJsonArray>
#include <QThread>
#include "worker.h"
#include <QPainter>
#include <QCameraInfo>

QT_BEGIN_NAMESPACE
namespace Ui { class ImageTest; }
QT_END_NAMESPACE

class ImageTest : public QWidget
{
    Q_OBJECT

public:
    ImageTest(QWidget *parent = nullptr);
    ~ImageTest();

signals:
    void begainWork(QImage img, QThread *childThread);     // 通知子线程干活

public slots:
    void showCamera(int id, QImage preview);    // 接收拍好照片的槽函数
    void takePicture();                         // 拍照按钮槽函数
    void tokenReply(QNetworkReply *reply);      // 网络请求回复槽函数
    void beginFaceDetect(QByteArray postData, QThread *overThread);  // 开始人脸识别
    void imgReply(QNetworkReply *reply);        // 图像识别网络请求回复槽函数

    void prePostData();
    void pickCamera(int idx);

private:
    Ui::ImageTest *ui;

    QCamera* camera;                        // 相机对象
    QCameraViewfinder* finder;              // 相机取景器对象
    QCameraImageCapture* imageCapture;      // 图像捕捉对象
    QTimer* refreshTimer;                   // 连续拍照定时器
    QTimer* netTimer;                       // 网络是被请求定时器
    QImage img;

    QNetworkAccessManager* tokenManager;    // token获取网络访问管理
    QNetworkAccessManager* imgManager;      // 图像识别网络访问管理
    QSslConfiguration sslConfig;            // ssl配置
    QString accessToken;

    QThread *childThread;

    double faceTop;
    double faceLeft;
    double faceWidth;
    double faceHeight;

    double age;
    QString gender;
    int mask;
    double beauty;

    QList<QCameraInfo> cameraInfoList;

    int latestTime;

};
#endif // IMAGETEST_H

4、imagetest.c

#include "imagetest.h"
#include "ui_imagetest.h"

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QNetworkAccessManager>

ImageTest::ImageTest(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::ImageTest)
{
    ui->setupUi(this);

    // 获取所有可用摄像头信息
    cameraInfoList = QCameraInfo::availableCameras();
    // 遍历输出相机信息
    for (const QCameraInfo &tmpCam:cameraInfoList)
    {
        qDebug() << tmpCam.deviceName() << "|||" << tmpCam.description();
        ui->comboBox->addItem(tmpCam.description());
    }

    connect(ui->comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ImageTest::pickCamera);

/*
 * 1 先有一个相机
 * 2 通过相机的取景器实时观察相机镜头内的图像
 * 3 通过图像捕捉,拍摄图像
*/
    camera = new QCamera();                         // 相机对象
    finder = new QCameraViewfinder();               // 相机取景器对象
    imageCapture = new QCameraImageCapture(camera); // 相机对应的图像捕捉对象

    camera->setViewfinder(finder);                  // 设置相机的取景器
    camera->setCaptureMode(QCamera::CaptureStillImage); // 设置图像捕捉模式:捕捉静态图像
    imageCapture->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);    // 设置捕捉的图片存到缓存

    // 拍照好之后QCameraImageCapture会发出一个拍照成功的信号,用一个槽函数接收信号,取出图片
    connect(imageCapture, &QCameraImageCapture::imageCaptured, this, &ImageTest::showCamera);

    // 识别按钮信号槽
    connect(ui->pushButton, &QPushButton::clicked, this, &ImageTest::prePostData);

    camera->start();        // 启动相机

    // 进行界面布局
    this->resize(1000, 600);                        // 整体界面大小

    QVBoxLayout* vboxl = new QVBoxLayout;           // 左边的垂直布局
    vboxl->addWidget(ui->label);                    // 将UI中的label加入到左边垂直布局
    vboxl->addWidget(ui->pushButton);               // 将UI中的pushButton加入到左边垂直布局

    QVBoxLayout* vboxr = new QVBoxLayout;           // 右边的垂直布局
    vboxr->addWidget(ui->comboBox);                 // 相机下拉列表
    vboxr->addWidget(finder);                       // 取景器加入到右边垂直布局
    vboxr->addWidget(ui->textBrowser);              // 将UI中的textBrowser加入到右边垂直布局

    QHBoxLayout* hbox = new QHBoxLayout(this);      // 整体水平布局
    hbox->addLayout(vboxl);                         // 左边的垂直布局加入到水平布局中
    hbox->addLayout(vboxr);                         // 右边的垂直布局加入到水平布局中

    this->setLayout(hbox);                          // 将hbox设置为界面布局

    // 利用定时器不断刷新拍照界面
    refreshTimer = new QTimer(this);
    connect(refreshTimer, &QTimer::timeout, this, &ImageTest::takePicture);
    refreshTimer->start(50);        // 启动定时器,周期ms

    // 利用定时器不断镜像人脸识别请求
    netTimer = new QTimer(this);
    connect(netTimer, &QTimer::timeout, this, &ImageTest::prePostData);

    // 网络访问,连接百度AI,用于图像识别
    tokenManager = new QNetworkAccessManager(this);
    // 网络请求返回信息处理
    connect(tokenManager, &QNetworkAccessManager::finished, this, &ImageTest::tokenReply);

    // 图像识别网络请求
    imgManager = new QNetworkAccessManager(this);
    connect(imgManager, &QNetworkAccessManager::finished, this, &ImageTest::imgReply);

    // 支持的协议,不支持https时需要安装库
    // Qt5.12: libcrypto-1_1-x64.dll  libssl-1_1-x64.dll
    // 系统中找到后复制到 F:\Qt\Qt5.12.9\5.12.9\mingw73_64\bin
    qDebug() << tokenManager->supportedSchemes();

    // 定义url
    QUrl url("https://aip.baidubce.com/oauth/2.0/token");
    qDebug() << url;
    // 键值队
    QUrlQuery query;
    query.addQueryItem("grant_type", "client_credentials");
    query.addQueryItem("client_id", "<你自己的client_id>");                // 替换成你自己的client_id
    query.addQueryItem("client_secret", "<你自己的client_secret>");    // 替换成你自己的client_secret
    // url添加键值队
    url.setQuery(query);
    qDebug() << url;

    ///ssl支持检查
    if(QSslSocket::supportsSsl())
    {
        qDebug() << "支持";
    }
    else
    {
        qDebug() << "不支持";
    }

    // ssl配置
    sslConfig = QSslConfiguration::defaultConfiguration();  // 使用默认配置
    sslConfig.setPeerVerifyMode(QSslSocket::QueryPeer);     // 模式
    sslConfig.setProtocol(QSsl::TlsV1_2);                   // 协议

    // 请求配置
    QNetworkRequest req;
    req.setUrl(url);                        // 设置url
    req.setSslConfiguration(sslConfig);     // 设置ssl配置信息

    // 发送get请求
    tokenManager->get(req);


}

ImageTest::~ImageTest()
{
    delete ui;
}

// 接收处理拍好的照片
void ImageTest::showCamera(int id, QImage img)
{
    Q_UNUSED(id)

    this->img = img;

    // 绘制人脸框
    QPainter p(&img);       // 创建绘图

    p.setPen(Qt::red);      // 画笔颜色
    p.drawRect(faceLeft, faceTop, faceWidth, faceHeight);   // 绘制矩形

    // 识别的信息显示在人脸旁边
    QFont font = p.font();
    font.setPixelSize(30);
    p.setFont(font);
    p.drawText(faceLeft+faceWidth+5, faceTop, QString("年龄:").append(QString::number(age)));
    p.drawText(faceLeft+faceWidth+5, faceTop+40, QString("性别:").append(gender));
    p.drawText(faceLeft+faceWidth+5, faceTop+80, QString("口罩:").append(mask==0?"没带口罩":"戴口罩了"));
    p.drawText(faceLeft+faceWidth+5, faceTop+120, QString("颜值:").append(QString::number(beauty)));

    ui->label->setPixmap(QPixmap::fromImage(img));      // 将拍好的图片转化成像素格式在label中显示
}

// 拍照
void ImageTest::takePicture()
{
    imageCapture->capture();
}

void ImageTest::tokenReply(QNetworkReply *reply)
{
    // 错误处理
    if (reply->error() != QNetworkReply::NoError)
    {
        qDebug() << reply->errorString();
        return;
    }

    // 正常应答
    const QByteArray reply_data = reply->readAll();

    // json解析
    QJsonParseError jsonErr;
    QJsonDocument doc = QJsonDocument::fromJson(reply_data, &jsonErr);

    if (jsonErr.error == QJsonParseError::NoError)
    {
        // 解析成功
        QJsonObject obj = doc.object();         // 获得JSON对象
        if (obj.contains("access_token"))
        {
            accessToken = obj.take("access_token").toString();
        }

        ui->textBrowser->setText(accessToken);
    }
    else
    {
        qDebug() << "JSON ERR:" << jsonErr.errorString();
    }

    reply->deleteLater();

    netTimer->start(1000);      // 定时器不断触发识别请求

//    prePostData();      // 连续循环检测     // 连续循环检测时取消改行注释

}

void ImageTest::prePostData()
{
    // 创建线程
    // 创建工人
    // 把工人送进子线程
    // 启动子线程
    // 给工人发通知干活

    childThread = new QThread(this);
    Worker *worker = new Worker;
    worker->moveToThread(childThread);

    // 通知线程干活
    connect(this, &ImageTest::begainWork, worker, &Worker::doWork);
    // 干完活的结果通知主线程
    connect(worker, &Worker::resultReady, this, &ImageTest::beginFaceDetect);
    // 子线程结束后删除子线程工人
    connect(childThread, &QThread::finished, worker, &Worker::deleteLater);

    childThread->start();

    emit begainWork(img, childThread);

}

// 相机切换槽函数
void ImageTest::pickCamera(int idx)
{
    qDebug() << cameraInfoList.at(idx).description();

    refreshTimer->stop();       // 刷新画面的计时器先停止
    camera->stop();             // 之前的相机先关掉

    // 创建新相机
    camera = new QCamera(cameraInfoList.at(idx));
    imageCapture = new QCameraImageCapture(camera);

    connect(imageCapture, &QCameraImageCapture::imageCaptured, this, &ImageTest::showCamera);

    imageCapture->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);
    camera->setCaptureMode(QCamera::CaptureStillImage);
    camera->setViewfinder(finder);

    camera->start();
    refreshTimer->start(100);
}

void ImageTest::beginFaceDetect(QByteArray postData, QThread *overThread)
{

    // 关闭子线程
    // 组装图像识别请求
    // 用post发送数据给百度AI

    overThread->exit();    // 结束线程
    overThread->wait();    // 等待线程结束
    if (childThread->isFinished())
    {
        qDebug() << "子线程结束了";
    }
    else
    {
        qDebug() << "子线程没结束";
    }

    // 3 组装图像识别请求
    QUrl url("https://aip.baidubce.com/rest/2.0/face/v3/detect");

    QUrlQuery query;
    query.addQueryItem("access_token", accessToken);    // URL参数
    url.setQuery(query);

    // ssl在初始化时已配置
    // 组装请求
    QNetworkRequest req;
    req.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));    // 请求头
    req.setUrl(url);                        // url
    req.setSslConfiguration(sslConfig);     // ssl

    // 发送post网络请求
    imgManager->post(req, postData);

}

void ImageTest::imgReply(QNetworkReply *reply)
{
    // 错误处理
    if (reply->error() != QNetworkReply::NoError)
    {
        qDebug() << reply->errorString();
        return;
    }

    // 正常应答
    const QByteArray replyData = reply->readAll();
    qDebug() << replyData;

    // json解析
    QJsonParseError jsonErr;
    QJsonDocument doc = QJsonDocument::fromJson(replyData, &jsonErr);

    // 解析成功
    if (jsonErr.error == QJsonParseError::NoError)
    {
        QString faceInfo;       // 用于存放解析出的人脸信息

        // 取出最外层json
        QJsonObject obj = doc.object();         // 获得JSON对象
        if(obj.contains("timestamp"))           // 获取时间用于判断是否最新一次人脸检测
        {
            int tmpTime = obj.take("timestamp").toInt();
            if (tmpTime < latestTime)           // 旧包,不处理(可能是网络等原因旧包后到达)
            {
                return;
            }
            else
            {
                latestTime = tmpTime;
            }
        }


        if (obj.contains("result"))             // 获取result内容
        {
            QJsonObject resultObj = obj.take("result").toObject();  // 将result转换为jsonObj

            // 取出人脸列表
            if (resultObj.contains("face_list"))
            {
                QJsonArray faceList = resultObj.take("face_list").toArray();  // 将face_list转换为QJsonArray
                QJsonObject faceObject = faceList.at(0).toObject();     // 取出数组中第一张人脸信息

                // 取出人脸定位信息
                if (faceObject.contains("location"))
                {
                    QJsonObject locObj = faceObject.take("location").toObject();
                    if (locObj.contains("left"))
                    {
                        faceLeft = locObj.take("left").toDouble();
                    }
                    if (locObj.contains("top"))
                    {
                        faceTop = locObj.take("top").toDouble();
                    }
                    if (locObj.contains("width"))
                    {
                        faceWidth = locObj.take("width").toDouble();
                    }
                    if (locObj.contains("height"))
                    {
                        faceHeight = locObj.take("height").toDouble();
                    }
                }

                // 取出年龄
                if(faceObject.contains("age"))
                {
                    age = faceObject.take("age").toDouble();
                    faceInfo.append("年龄:").append(QString::number(age)).append("\r\n");     // 年龄信息存入
                    qDebug() << "age";
                }

                // 取出性别
                if(faceObject.contains("gender"))
                {
                    QJsonObject genderObj = faceObject.take("gender").toObject();
                    if (genderObj.contains("type"))
                    {
                        gender = genderObj.take("type").toString();
                        faceInfo.append("性别:").append(gender).append("\r\n");       // 性别信息存入
                        qDebug() << "gender";
                    }
                }

                // 取出表情
                if(faceObject.contains("emotion"))
                {
                    QJsonObject emotionObj = faceObject.take("emotion").toObject();
                    if (emotionObj.contains("type"))
                    {
                        QString emotion = emotionObj.take("type").toString();
                        faceInfo.append("表情:").append(emotion).append("\r\n");       // 表情信息存入
                        qDebug() << "emotion";
                    }
                }

                // 取出是否戴口罩
                if(faceObject.contains("mask"))
                {
                    QJsonObject maskObj = faceObject.take("mask").toObject();
                    if (maskObj.contains("type"))
                    {
                        mask = maskObj.take("type").toInt();
                        faceInfo.append("口罩:").append(mask==0?"没带口罩":"戴口罩了").append("\r\n");       // 表情信息存入
                        qDebug() << "mask";
                    }
                }

                // 取出颜值
                if(faceObject.contains("beauty"))
                {
                    beauty = faceObject.take("beauty").toDouble();
                    faceInfo.append("颜值:").append(QString::number(beauty)).append("\r\n");     // 年龄信息存入
                    qDebug() << "beauty";
                }

            }
        }
        // 信息框中显示
        ui->textBrowser->setText(faceInfo);
        qDebug() << faceInfo;
    }
    else
    {
        qDebug() << "JSON ERR:" << jsonErr.errorString();
    }

    reply->deleteLater();

//    prePostData();        // 连续循环检测   // 连续循环检测时取消改行注释

}



5、worker.h

#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <QImage>
#include <QThread>

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);

public slots:
    void doWork(QImage img, QThread *childThread);

signals:
    void resultReady(QByteArray pd, QThread *childThread);

};

#endif // WORKER_H

6、worker.cpp

#include "worker.h"
#include <QBuffer>
#include <QJsonObject>
#include <QJsonDocument>


Worker::Worker(QObject *parent) : QObject(parent)
{

}

void Worker::doWork(QImage img, QThread *childThread)
{
    // 1 转成base64编码图片
    QByteArray ba;                      // 字节数组
    QBuffer buff(&ba);                  // 为字节数组提供一个buff,类似文件IO,内存操作
    img.save(&buff, "png");             // 以png格式保存图片
    QString b64str = ba.toBase64();     // 将图片转换为Base64编码
    // qDebug() << b64str;

    // 百度要求JSON格式post发送
    // 2 请求体body参数设置
    QJsonObject postJson;
    QJsonDocument doc;

    // 插入键值对
    postJson.insert("image", b64str);
    postJson.insert("image_type", "BASE64");
    postJson.insert("face_field", "age,expression,face_shape,gender,glasses,emotion,face_type,mask,beauty");

    doc.setObject(postJson);                // 放入doc内
    QByteArray postData = doc.toJson(QJsonDocument::Compact);     // 打包转换为json字节数组

    emit resultReady(postData, childThread);         // 通知主线程
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Qt是一个跨平台的应用程序开发框架,而百度AI则是百度公司提供的人工智能服务平台。要实现Qt调用百度AI的人脸识别解锁功能,可以按照以下步骤进行: 1. 首先,在百度AI平台上注册一个账号,并创建一个人脸识别的应用。获取该应用的API Key和Secret Key,以便后续使用。 2. 在Qt项目中,引入百度AI提供的SDK(软件开发工具包),这个SDK可以提供与百度AI平台进行通信的接口。 3. 在Qt代码中,使用SDK提供的函数调用方式,实现人脸识别解锁功能。具体步骤如下: a. 初始化百度AI SDK,将API Key和Secret Key传入进行认证。 b. 将待识别的人脸图像传入SDK的人脸检测接口,提取图像中的人脸信息。 c. 将提取到的人脸信息传入SDK的人脸比对接口,与已注册的人脸信息进行比对。 d. 根据比对结果,判断是否为有效用户,进而进行解锁操作。 4. 在Qt界面中集成该人脸识别解锁功能,可以通过摄像头实时捕捉人脸图像,并调用SDK进行人脸识别。在界面上展示识别结果,如解锁成功或失败的提示。 总的来说,Qt调用百度AI的人脸识别解锁需要引入百度AI提供的SDK,并通过SDK提供的接口函数实现人脸检测和比对的功能。在Qt界面中通过摄像头捕捉人脸图像,进行实时的人脸识别操作,以实现人脸识别解锁。 ### 回答2: Qt是一款功能强大的跨平台应用程序开发框架,可以用于开发各种类型的应用程序,包括人脸识别解锁功能。而百度AI的人脸识别技术是一种基于人脸图像进行人脸检测、人脸比对和人脸搜索的先进技术。下面将介绍如何使用Qt调用百度AI的人脸识别解锁。 首先,我们需要在百度AI开放平台上注册账号并创建一个人脸识别应用。在创建应用后,我们将得到一个API Key和Secret Key,这将用于调用百度AI的人脸识别接口。 接下来,在Qt中创建一个新的项目。我们可以使用Qt提供的网络请求类QNetworkAccessManager来发送HTTP请求。通过发送HTTP POST请求到百度AI的人脸识别接口,将待识别的人脸图像数据传输给服务器。 在调用人脸识别接口时,需要注意接口的请求参数。首先,需要指定人脸识别接口的URL,以及携带API Key和Secret Key的请求头信息。其次,在请求体中,需要传输待识别的人脸图像数据。可以将人脸图像数据进行Base64编码后作为请求参数发送。同时,可以指定一些可选的参数,如人脸识别的阈值、检测的最大人脸数等。发送请求后,服务器会返回一个识别结果,我们可以根据接口返回的JSON数据进行解析和处理,以获取人脸识别的结果。 最后,在Qt的界面中添加一个调用人脸识别解锁功能的按钮。当用户点击该按钮时,应用程序将调用百度AI的人脸识别接口进行解锁验证。根据接口返回的结果,我们可以判断是否解锁成功,并在界面中显示相应的提示信息。 总之,通过Qt调用百度AI的人脸识别解锁,我们可以实现一种安全、快速的人脸识别解锁功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值