c++/qt连接阿里云视觉智能开发平台

news2024/11/4 19:56:44

官方参考文档:

        阿里云人脸活体检测api文档:调用DetectLivingFace进行人脸活体检测_视觉智能开放平台(VIAPI)-阿里云帮助中心

        阿里云视觉智能平台公共请求参数文档:人体人脸分析API接口的公共请求参数_视觉智能开放平台(VIAPI)-阿里云帮助中心

        这个公共请求参数文档里面,官方给了完整的java代码,用于请求人脸活体检测接口,但是阿里云官方对c++的支持很弱,没有c++相关的示例,这篇文章就是根据这个官方java示例,给出qt/c++的代码


先给出完整qt代码
头文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QImage>
#include <QNetworkAccessManager>
#include <QNetworkReply>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void on_imgBtn_clicked();

private:
    Ui::MainWindow *ui;

    QNetworkAccessManager *_manager = nullptr;
    QUrl url;

    void doAliDetectLivingFace();
    QString specialUrlEncode(const QString &value);
    QString sign(const QString &accessSecret, const QString &stringToSign);
    QString sign2(const QString &accessSecret, const QString &stringToSign);

private slots:
    void finishedReplay();
    void downloadProgress(qint64 bytesSent, qint64 bytesTotal);
    void slotError(QNetworkReply::NetworkError net_error);
};

#endif // MAINWINDOW_H

cpp 文件:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QBuffer>
#include <QFileInfo>
#include <QCryptographicHash>
#include <QDebug>
#include <QFileDialog>
#include <QUrlQuery>
#include <QUuid>
#include <QMessageAuthenticationCode>
#include <QTimeZone>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    _manager =new QNetworkAccessManager(this);
    doAliDetectLivingFace();
}

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

void MainWindow::finishedReplay()
{
    QNetworkReply *reply = dynamic_cast<QNetworkReply*>(sender());
    QByteArray bytes = reply->readAll();

    qDebug()<<"finished:\n";
    QString  html_text = bytes;
    qDebug()<<"get ready,read size:"<<html_text.size();
    qDebug()<< "ret_html_text:\n"<<html_text<<"\n";
    reply->deleteLater();
}

void MainWindow::downloadProgress(qint64 bytesSent, qint64 bytesTotal)
{
    qDebug()<< "\ndownloadProgress done:\n";
    qDebug() << "bytesSent: " << bytesSent<< "  " << "bytesTocal: " << bytesTotal;
}

void MainWindow::slotError(QNetworkReply::NetworkError net_error)
{
    qDebug()<< "slotError:"<<net_error;
}

void MainWindow::doAliDetectLivingFace()
{
    /*
    最终url:
    http://facebody.cn-shanghai.aliyuncs.com/?Signature=olXJ3UlVH4bSG1OHrg3kQWE0lrE%3D
        &AccessKeyId=LTAI5tFopUsaPTXZCvSdrkpQ
        &Action=DetectLivingFace
        &Format=JSON
        &RegionId=cn-shanghai
        &SignatureMethod=HMAC-SHA1
        &SignatureNonce=2a90f9ef-9d6d-438e-b20f-5106653654d2
        &SignatureVersion=1.0
        &Tasks.1.ImageURL=http%3A%2F%2Fviapi-test.oss-cn-shanghai.aliyuncs.com%2Fviapi-3.0domepic%2Ffacebody%2FDetectLivingFace%2FDetectLivingFace11.jpg
        &Tasks.2.ImageURL=http%3A%2F%2Fviapi-test.oss-cn-shanghai.aliyuncs.com%2Fviapi-3.0domepic%2Ffacebody%2FDetectLivingFace%2FDetectLivingFace13.jpg
        &Timestamp=2024-10-31T09%3A03%3A08Z
        &Version=2019-12-30
    */

    QDateTime currentTime = QDateTime::currentDateTime();
    QDateTime eightHoursAgo = currentTime.addSecs(-8 * 3600);
    QTimeZone gmtTimeZone("GMT");
    eightHoursAgo.setTimeZone(gmtTimeZone);
    QString currentTimeStr = eightHoursAgo.toString("yyyy-MM-dd'T'HH:mm:ss'Z'");
    
    // 这里换成自己阿里云账户的accessKeyId和accessKeySecret
    QString accessKeyId = "***************";
    QString  accessKeySecret = "***************";

    QMap<QString, QString> urlQueryMap;

    urlQueryMap.insert("Tasks.1.ImageURL", "http://viapi-test.oss-cn-shanghai.aliyuncs.com/viapi-3.0domepic/facebody/DetectLivingFace/DetectLivingFace11.jpg");
    urlQueryMap.insert("Tasks.2.ImageURL", "http://viapi-test.oss-cn-shanghai.aliyuncs.com/viapi-3.0domepic/facebody/DetectLivingFace/DetectLivingFace13.jpg");
    urlQueryMap.insert("SignatureMethod", "HMAC-SHA1");

    QUuid uuid = QUuid::createUuid();
    QString uuidString = uuid.toString();
    uuidString = uuidString.mid(1, uuidString.size() -2);
    // urlQueryMap.insert("SignatureNonce", "4449ddb6-d72a-4e56-899c-c33365a8caf2");
    urlQueryMap.insert("SignatureNonce", uuidString);
    urlQueryMap.insert("AccessKeyId", accessKeyId);
    urlQueryMap.insert("SignatureVersion", "1.0");
    // urlQueryMap.insert("Timestamp", "2024-10-28T02:02:26Z");
    urlQueryMap.insert("Timestamp", currentTimeStr);
    urlQueryMap.insert("Format", "JSON");
    urlQueryMap.insert("RegionId", "cn-shanghai");
    urlQueryMap.insert("Version", "2019-12-30");
    urlQueryMap.insert("Action", "DetectLivingFace");
    // urlQueryMap.insert("ImageURL", "https://ainemo-testdev.oss-cn-beijing.aliyuncs.com/wenkeTest/1.png");
    if (urlQueryMap.contains("Signature")) {
        urlQueryMap.remove("Signature");
    }

    QString sortQueryStringTmp;
    for(auto it = urlQueryMap.begin(); it != urlQueryMap.end(); ++it)
    {
        sortQueryStringTmp.append("&").append(specialUrlEncode(it.key())).append("=").append(specialUrlEncode(it.value()));
    }

    QString sortedQueryString = sortQueryStringTmp.mid(1);

    QString stringToSign;
    stringToSign.append("POST").append("&");
    stringToSign.append(specialUrlEncode("/")).append("&");
    stringToSign.append(specialUrlEncode(sortedQueryString));

    // QString signStr = QString::fromStdString(SignUtil::sign(QString(accessKeySecret + "&").toStdString(), stringToSign.toStdString()));
    // signStr = signStr.left(signStr.size() - 1);
    QString signStr = sign(accessKeySecret + "&", stringToSign);
    QString signature = specialUrlEncode(signStr);

    QString urlStr = QString("http://facebody.cn-shanghai.aliyuncs.com/?Signature=%1&%2").arg(signature, sortedQueryString);

    // qDebug() << "timeStamp is " << "2024-10-28T02:02:26Z";
    qDebug() <<"sortedQueryString is " << sortedQueryString;
    qDebug() <<"stringToSign is " << stringToSign;
    qDebug() <<"signStr is " << signStr;
    qDebug() <<"signature is " << signature;
    qDebug() << "url str is " << urlStr;

    QNetworkRequest request;
    QString accept = "application/json";
    QString content_type = "application/json";
    request.setRawHeader(QByteArray("accept"), accept.toLocal8Bit());
    request.setHeader(QNetworkRequest::ContentTypeHeader,content_type);
    request.setUrl(QUrl(urlStr));

    QNetworkReply *reply = _manager->post(request, "");
    connect(reply, SIGNAL(finished()), this, SLOT(finishedReplay()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
            this, SLOT(slotError(QNetworkReply::NetworkError)));
    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),
            this,SLOT(downloadProgress(qint64,qint64)));
}

QString MainWindow::specialUrlEncode(const QString &value)
{
    QString encodedValue = QUrl::toPercentEncoding(value, "", "");
    encodedValue.replace("+", "%20");
    encodedValue.replace("*", "%2A");
    encodedValue.replace("%7E", "~");
    return encodedValue;
}

QString MainWindow::sign(const QString &accessSecret, const QString &stringToSign)
{
    QByteArray key = accessSecret.toUtf8();
    QByteArray data = stringToSign.toUtf8();

    int blockSize = 64; // HMAC-SHA1 block size
    if (key.length() > blockSize) {
        key = QCryptographicHash::hash(key, QCryptographicHash::Sha1);
    } else if (key.length() < blockSize) {
        key = key.leftJustified(blockSize, '\0');
    }

    QByteArray ipad(blockSize, 0x36);
    QByteArray opad(blockSize, 0x5c);

    // XOR key with inner and outer padding
    for (int i = 0; i < blockSize; i++) {
        ipad[i] = ipad[i] ^ key.at(i);
        opad[i] = opad[i] ^ key.at(i);
    }

    QByteArray innerHash = QCryptographicHash::hash(ipad + data, QCryptographicHash::Sha1);
    QByteArray finalData = opad + innerHash;

    QByteArray signData = QCryptographicHash::hash(finalData, QCryptographicHash::Sha1);

    // Encode the result in Base64
    QByteArray base64SignData = signData.toBase64();

    return QString(base64SignData);
}

QString MainWindow::sign2(const QString &accessSecret, const QString &stringToSign)
{
    QByteArray key = accessSecret.toUtf8();
    QByteArray data = stringToSign.toUtf8();

    // Calculate HMAC-SHA1
    QByteArray signData = QMessageAuthenticationCode::hash(data, key, QCryptographicHash::Sha1);

    // Encode the result in Base64
    QByteArray base64SignData = QByteArray(signData).toBase64();

    return QString(base64SignData);
}


void MainWindow::on_imgBtn_clicked()
{
    QString imgPath = QFileDialog::getOpenFileName(this, "select image", "", tr("Images (*.png *.xpm *.jpg)"));
    doAliDetectLivingFace();
    ui->imgLineEdit->setText(imgPath);
}

        关键就是doAliDetectLivingFace函数,里面有几个细节:
1、时间的获取需要比当前时间早8个小时

2、注意stringToSign获取细节,url的query需要按字母顺序排序好,同时需要经specialUrlEncode,这一块自己仔细看代码

3、获取认证字符串的函数sign、sign2都可以使用,是一样的结果,其中sign函数呈现了更多细节

        另外,考虑到有些开发者只熟悉原生c++,不熟悉qt,而上面sign函数是关键,其它地方都好写出替代代码,所以这里给出用openssl实现的sign函数,qt的开发者可以不管这个
 

std::string SignUtil::sign(const std::string &accessSecret, const std::string &stringToSign)
{
    unsigned char hash[EVP_MAX_MD_SIZE];
    unsigned int hashLen = 0;

    // 初始化HMAC上下文
    HMAC_CTX* hmacCtx = HMAC_CTX_new();
    HMAC_Init_ex(hmacCtx, accessSecret.c_str(), accessSecret.length(), EVP_sha1(), NULL);

    // 更新HMAC上下文
    HMAC_Update(hmacCtx, (const unsigned char *)stringToSign.c_str(), stringToSign.length());

    // 完成HMAC计算
    HMAC_Final(hmacCtx, hash, &hashLen);

    // 释放HMAC上下文
    HMAC_CTX_free(hmacCtx);

    // 创建一个Base64编码器
    BIO* bio = BIO_new(BIO_s_mem());
    BIO* b64 = BIO_new(BIO_f_base64());
    bio = BIO_push(b64, bio);

    // 将哈希值写入BIO
    BIO_write(bio, hash, hashLen);
    BIO_flush(bio);

    // 从BIO读取Base64编码后的字符串
    BUF_MEM* buffer;
    BIO_get_mem_ptr(bio, &buffer);
    std::string base64Encoded(buffer->data, buffer->length);

    // 清理BIO
    BIO_free_all(bio);

    return base64Encoded;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2232040.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32H750 USBCDC配置与使用

STM32H750 USBCDC配置与使用 &#x1f4cd;相关参考文章&#xff1a;《STM32 USB CDC VPC》 STM32H750VB有2个USB OTG接口&#xff08;1FS&#xff0c;1HS/FS&#xff09;无晶振型解决方案&#xff0c;带有LPM和BCD。 &#x1f516;本次使用USB-PTG-FS作为测试 &#x1f33f;…

引领数字时代:万码优才如何变革IT人才招聘新体验(这里有更精准的推荐)

目录 引领数字时代&#xff1a;万码优才如何变革IT人才招聘新体验引领未来科技&#xff0c;精准链接IT精英精准匹配&#xff0c;高效对接海量资源&#xff0c;覆盖广泛优化体验&#xff0c;简化流程 全面升级&#xff1a;AI赋能数字人才职业成长AI模拟面试职场千问智能简历评估…

网络安全法详细介绍——爬虫教程

目录 [TOC](目录)一、网络安全法详细介绍1. 网络安全法的主要条款与作用2. 网络安全法与爬虫的关系3. 合法使用爬虫的指南 二、爬虫的详细教程1. 准备环境与安装工具2. 使用requests库发送请求3. 解析HTML内容4. 使用robots.txt规范爬虫行为5. 设置请求间隔6. 数据清洗与存储 三…

vscode插件-08 Golang

文章目录 Go安装其他必须软件 Go Go语言环境&#xff0c;只需安装这一个插件。然后通过vscode命令下载安装其他go环境需要的内容。 程序调试&#xff0c;需要创建.vscode文件夹并编写launch.json文件。 安装其他必须软件 ctrlshiftp&#xff0c;调出命令面板&#xff0c;输入…

ConnectX-7 25/50/100/200/400G NIC

ConnectX-7 25/50/100/200/400G NIC ConnectX-7提供了广泛的软件定义、硬件加速的网络、存储和安全功能&#xff0c;使组织能够现代化和保护他们的IT基础设施。此外&#xff0c;ConnectX-7还支持从边缘到核心数据中心到云的敏捷和高性能解决方案&#xff0c;同时增强网络安全性…

windows在两台机器上测试 MySQL 集群实现实时备份

在两台机器上测试 MySQL 集群实现实时备份的基本步骤&#xff1a; 一、环境准备 机器配置 确保两台机器&#xff08;假设为服务器 A 和服务器 B&#xff09;能够互相通信&#xff0c;例如它们在同一个局域网内&#xff0c;并且开放了 MySQL 通信所需的端口&#xff08;默认是 …

uniapp实现中间平滑凸起tabbar

uniapp实现中间平滑凸起tabbar 背景实现思路代码实现尾巴 背景 在移动端开发中&#xff0c;tabar是一个使用频率很高的组件&#xff0c;几乎是每个APP都会用到。今天给大家分享一个中间平滑凸起的tabbar组件&#xff0c;有需要的可以做下参考。先上图镇楼&#xff1a; 实现思…

java版询价采购系统 招投标询价竞标投标系统 招投标公告系统源码

在数字化时代&#xff0c;企业需要借助先进的数字化技术来提高工程管理效率和质量。招投标管理系统作为企业内部业务项目管理的重要应用平台&#xff0c;涵盖了门户管理、立项管理、采购项目管理、采购公告管理、考核管理、报表管理、评审管理、企业管理、采购管理和系统管理等…

YOLOV8目标检测C++推理问题总结

背景 数据集有限&#xff0c;使用paddleOCR直接识别准确率无法达到99%&#xff0c;这里尝试用目标检测对识别得分比较低的图片进行二次处理&#xff1b; 类别数目&#xff1a;数字&#xff08;10&#xff09;字母&#xff08;26&#xff09;字符&#xff08;2&#xff09; 38 …

Python毕业设计选题:基于Hadoop的租房数据分析系统的设计与实现

开发语言&#xff1a;Python框架&#xff1a;flaskPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页 房屋信息详情 个人中心 管理员登录界面 管理员功能界面 用户管理界面 房屋信…

CSRF与SSRF

csrf(跨站请求伪造)的原理: csrf全称是跨站请求伪造(cross-site request forgery)&#xff0c;也被称为one-click attack 或者 session riding scrf攻击利用网站对于用户网页浏览器的信任&#xff0c;劫持用户当前已登录的web应用程序&#xff0c;去执行分用户本意的操作。 利…

Rust 力扣 - 1984. 学生分数的最小差值

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 原数组 nums 排序&#xff0c;遍历nums中下标为[0, nums.len() - k]的学生分数 假设当前遍历的下标为i则&#xff0c;以 i 下标为最小值的学生分数的最小差值为nums[i k - 1] - nums[i] 取最小差值的最小值即…

前端笔试新问题总结

记录总结下最近遇到的前端笔试新问题 目录 一、操作数组方法 1.Array.isArray(arr) 2.Object.prototype.toString.call(arr) "[object Array]" 3.arr instanceof Array 1&#xff09;跨帧问题 2&#xff09;修改Array.prototype 3&#xff09;模拟数组的对象…

HTML 基础标签——结构化标签<html>、<head>、<body>

文章目录 1. <html> 标签2. <head> 标签3. <body> 标签4. <div> 标签5. <span> 标签小结 在 HTML 文档中&#xff0c;使用特定的结构标签可以有效地组织和管理网页内容。这些标签不仅有助于浏览器正确解析和渲染页面&#xff0c;还能提高网页的可…

跳表原理笔记

课程地址 跳表是一种基于随机化的有序数据结构&#xff0c;它提出是为了赋予有序单链表以 O(logn) 的快速查找和插入的能力 创建 首先在头部创建一个 sentinel 节点&#xff0c;然后在 L1 层采用“抛硬币”的方式来决定 L0 层的指针是否增长到 L1 层 例如上图中&#xff0c;L…

Vision - 开源视觉分割算法框架 Grounded SAM2 配置与推理 教程 (1)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/143388189 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Ground…

3674矢量网络分析仪-003噪声系数测量选件

3674X-003 噪声系数测量选件 3674系列矢量网络分析仪 综述 3674X-003噪声系数测量一次连接&#xff0c;可同时测试S参数、噪声系数、噪声参数、增益压缩和变频增益等多种参数。基于冷源噪声系数测试方法&#xff0c;可进行精确的噪声系数和噪声参数测试。 •特点 • 3674X…

DDRPHY数字IC后端设计实现系列专题之后端设计导入,IO Ring设计

本章详细分析和论述了 LPDDR3 物理层接口模块的布图和布局规划的设计和实 现过程&#xff0c;包括设计环境的建立&#xff0c;布图规划包括模块尺寸的确定&#xff0c;IO 单元、宏单元以及 特殊单元的摆放。由于布图规划中的电源规划环节较为重要&#xff0c; 影响芯片的布线资…

如何将MySQL彻底卸载干净

目录 背景&#xff1a; MySQL的卸载 步骤1&#xff1a;停止MySQL服务 步骤2&#xff1a;软件的卸载 步骤3&#xff1a;残余文件的清理 步骤4&#xff1a;清理注册表 步骤五:删除环境变量配置 总结&#xff1a; 背景&#xff1a; MySQL卸载不彻底往往会导致重新安装失败…

Vue生成名片二维码带logo并支持下载

一、需求 生成一张名片&#xff0c;名片上有用户信息以及二维码&#xff0c;名片支持下载功能&#xff08;背景样式可更换&#xff0c;忽略本文章样图样式&#xff09;。 二、参考文章 这不是我自己找官网自己摸索出来的&#xff0c;是借鉴各位前辈的&#xff0c;学以致用&am…