qt5.8(c++)实现阿里云人脸识别云接口

简介: 阿里云提供了人脸识别的api,其示例除了c/c++,其他主流语言都有相应的实例。 本人由于项目债务和集成需要,需要用c/c++实现,若只是支持win/Linux平台,采用 acl_master源码库也可行,有需要的可参考《阿里云短信服务接口的c++实现》, 阿里云的短信服务接口与人脸识别在数据签名、加密等方面是一致的。

阿里云提供了人脸识别的api,其示例除了c/c++,其他主流语言都有相应的实例。

本人由于项目债务和集成需要,需要用c/c++实现,若只是支持win/Linux平台,采用

acl_master源码库也可行,有需要的可参考《阿里云短信服务接口的c++实现》,

阿里云的短信服务接口与人脸识别在数据签名、加密等方面是一致的。

我当前项目由于跨平台支持android编译,所以采用了qt实现阿里云的人脸识别接口。

备注:若需要静态编译实现阿里云的人脸识别,可能 qt环境需要重新静态编译network模块,追加openssl静态编译支持,

更细节的实现可以参考《qt5.8_for_vs2015 and openssl静态编译 》。

阿里云的人脸识别主要有两个难点,其一是,若你直接传输图片内容,需要对图片内容进行编码,其二是需要实现签名认证。

下面就如何实现阿里云的人脸属性识别的过程(人脸检测定位、人脸比对类似):

1)首先需要开通 阿里云 的人脸识别服务,下面是本人在阿里云的云产品通用代金券链接:

https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pfb80n4a

开通服务后,进入 人脸识别的控制台,在其左侧栏目有个API调试,点击进去,这里标注的

请求地址是我们需要用到的,例如:https://dtplus-cn-shanghai.data.aliyuncs.com/face/attribute

另外 Access Key ID和Access Key Secret在API调用也需要,在你的头像下的AccessKeys项点击进去获取即可。

2)阿里API说明手册指出,若图片内容指定url,需要你只身配备网络存储路径,采用阿里的OSS也是不错的选择,若直接传输图片内容,需要采用base64编码,刚好qt5.8就能直接实现,下面就直接传输本地图片内容进行阿里云人脸识别API调用,记得qt工程文件需要添加,

QT += network

示例代码:

QByteArray  FaceDetectObject::Image_To_Base64(QString image_path)
{
    QImage image(image_path);
    QByteArray ba;
    QBuffer buf(&ba);
    image.save(&buf,"jpg");
    QByteArray hexed = ba.toBase64();
    buf.close();
    return hexed;
}

 

3)关于人脸识别的通信接口的签名的细节要求查看官方说明文档《API校验规范》章节,其内容要求UTF-8和Base64编码,签名算法遵循RFC 2104HMAC-SHA1规范。

MD5转换示例代码:

QByteArray FaceDetectObject::getMD5(QByteArray bytes_)
{
    QCryptographicHash ch(QCryptographicHash::Md5);
    QByteArray ret;
    ch.addData(bytes_);
    ret = ch.result();
    return ret;
}

 

HMACSha1算法示例代码:
QByteArray FaceDetectObject::HMACSha1(QByteArray key, QByteArray baseString)
 {
     int blockSize = 64;                // HMAC-SHA-1 block size, defined in SHA-1 standard
     if (key.length() > blockSize) {    // if key is longer than block size (64), reduce key length with SHA-1 compression
         key = QCryptographicHash::hash(key, QCryptographicHash::Sha1);
     }
     QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"
     QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "/"
     // ascii characters 0x36 ("6") and 0x5c ("/") are selected because they have large
     // Hamming distance (http://en.wikipedia.org/wiki/Hamming_distance)
     for (int i = 0; i < key.length(); i++) {
         innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key length
         outerPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length
     }
     // result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64
     QByteArray total = outerPadding;
     QByteArray part = innerPadding;
     part.append(baseString);
     total.append(QCryptographicHash::hash(part, QCryptographicHash::Sha1));
     QByteArray hashed = QCryptographicHash::hash(total, QCryptographicHash::Sha1);
          /// 注意——>把字符串hashed转换为Hex,内存中的ASCII码arrayFromHexString
     QByteArray arrayFromHexString = QByteArray::fromHex(hashed.toHex());
     qDebug()<<"hmacSha1内存中的ASCII码 arrayFromHexString \n"<<arrayFromHexString.toHex();
     return arrayFromHexString;
}

4)阿里云一般对于http协议的时间格式要求是GMT的

也就是QT里面的UTC格式, 实现 样例:

QLocale lo = QLocale::English;//设置QLocale为英文
    QString date = lo.toString(QDateTime::currentDateTimeUtc(),"ddd, dd MMM yyyy hh:mm:ss")+QString(" GMT");

其通信协议需要openssl支持才能实现https请求,实现 样例:

    QNetworkRequest request;
    QSslConfiguration config;
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1_0);
    request.setSslConfiguration(config);

5)实现阿里云的人脸属性识别请求,记得把key和密钥换成自己的:

void FaceDetectObject::do_post_al(QByteArray bytearray)
{
    qDebug()<<"img_bytearray_size="<<bytearray.size()<<"\n";
//    qDebug()<<"img_bytearray="<<bytearray.data()<<"\n";
    url = QUrl("https://dtplus-cn-shanghai.data.aliyuncs.com/face/attribute",QUrl::TolerantMode);
//    url.toEncoded();
    qDebug() <<"url="<<url.url()<<"\n";
    QString ak_id = "**************";                //you key
    QString ak_secret = "**************************";//you secret
    /*
     * http header 参数
     */
    QString method = "POST";
    QString accept = "application/json";
    QString content_type = "application/json";
    QLocale lo = QLocale::English;//设置QLocale为英文
    QString date = lo.toString(QDateTime::currentDateTimeUtc(),"ddd, dd MMM yyyy hh:mm:ss")+QString(" GMT");
    qDebug() <<"date = " << date <<"\n";
    //1.对body做MD5+BASE64加密
    QByteArray body = QString("{\"type\":\"1\",\"content\":\"%1\"}").arg(bytearray.data()).toLocal8Bit();
    qDebug() <<"body = " << body <<"\n";
    QByteArray bodyMd5 = getMD5(body);
    qDebug() <<"bodyMd5 = " << bodyMd5 <<"\n";
    QString bodyBase64 = bodyMd5.toBase64();
    qDebug() <<"bodyBase64 = " << bodyBase64 <<"\n";
    QString stringToSign = method + "\n" + accept + "\n" + bodyBase64 + "\n" + content_type + "\n" + date + "\n"+ url.path();
    qDebug() << "stringToSign="<<stringToSign<<"\n";
    // 2.计算 HMAC-SHA1
    QString signature = HMACSha1(ak_secret.toLocal8Bit(),stringToSign.toLocal8Bit()).toBase64();
    qDebug() << "signature="<<signature<<"\n";
    // 3.得到 authorization header
    QString authHeader = "Dataplus " + ak_id + ":" + signature;
    qDebug() << "authHeader="<<authHeader<<"\n";
    QNetworkRequest request;
//    request.sslConfiguration().setPeerVerifyMode(QSslSocket::VerifyNone);
//    request.sslConfiguration().setProtocol(QSsl::TlsV1_0);

    QSslConfiguration config;
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1_0);
    request.setSslConfiguration(config);

    request.setUrl(url);
    request.setRawHeader(QByteArray("accept"), accept.toLocal8Bit());
    request.setHeader(QNetworkRequest::ContentTypeHeader,content_type);
    request.setRawHeader(QByteArray("date"), date.toLocal8Bit());
    request.setRawHeader(QByteArray("Authorization"), authHeader.toLocal8Bit());
//    request.setRawHeader(QByteArray("Connection"), QByteArray("keep-alive"));
    if(reply != Q_NULLPTR) {//更改reply指向位置钱一定要保证之前的定义了自动delete
        reply->deleteLater();
    }
    reply = manager->post(request,body);
//            connect(reply, &QNetworkReply::finished, this, &FaceDetectThread::finishedReplay);
    connect(reply, SIGNAL(finished()), this, SLOT(finishedReplay()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
              this, SLOT(slotError(QNetworkReply::NetworkError)));
//            connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
//                      this, SLOT(slotSslErrors(QList<QSslError>)));
    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),
            this,SLOT(downloadProgress(qint64,qint64)));
    qDebug() << "start post_al";
}

备注:bytearray是base64的图片内容

6)请求返回的数据为JSON格式 描述,字段描述细节参考官方的人脸属性识别API 调用说明,内容有点多,我就不截图。

返回数据获取示例代码如下:

void FaceDetectObject::finishedReplay()
{
    QByteArray bytes = reply->readAll();
    const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
    reply->deleteLater();
    reply = Q_NULLPTR;
    if (!redirectionTarget.isNull()) {//如果网址跳转重新请求
        const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl());
        qDebug()<<"redirectedUrl:"<<redirectedUrl.url()<<"\n";
        url = redirectedUrl;
        qDebug()<<"new_url="<<url.toString().toLocal8Bit()<<"\n";
        //写出新url,测试使用
        QFile f("url_.txt");//写出文件
        f.open(QFile::WriteOnly);
        f.write(url.toString().toLocal8Bit());
        f.close();
        return;
    }
    qDebug()<<"finished:\n";
    QString  html_text = bytes;
    qDebug()<<"get ready,read size:"<<html_text.size();
    qDebug()<< "ret_html_text:\n"<<html_text<<"\n";
    //保存结果,测试使用
    QFile f("result.html");//写出文件
    f.open(QFile::WriteOnly);
    f.write(bytes);
    f.close();
}

返回结果示例:

{"face_num":1,"face_rect":[391,365,94,127],"face_prob":[1.0],"pose":[5.843783378601074,-3.454075336456299,2.8692541122436523],"landmark_num":105,"landmark":[..展示需要删除..],"iris":[417.10675048828125,415.4582214355469,4.029685020446777,460.1661071777344,418.9272155761719,4.029685020446777],"gender":[0],"age":[28],"expression":[0],"glass":[0],"dense_fea_len":1024,"dense_fea":"[..展示需要删除..]","errno":0,"request_id":"3bad9b68-b337-4c07-8661-403178948a31"}

取得返回结果后就是 业务应用的范畴了,人脸检测定位、人脸比对实现类似。基于我的业务逻辑只需要脸数、性别、年龄、笑容,示例代码如下:

//输入参数来自:QByteArray bytes = reply->readAll();
void FaceDetectObject::JsonDecode(QByteArray bytes)
{
    QJsonParseError json_error;
    QJsonDocument retVals = QJsonDocument::fromJson(bytes,&json_error);
    if(json_error.error == QJsonParseError::NoError)
    {
        if(retVals.isObject())
        {
            int face_num_val=0 ;
            QVector<bool> genders;
            QVector<int> ages;
            QVector<bool> expressions;
            QJsonObject obj = retVals.object();
            if(obj.contains("face_num"))
            {
                QJsonValue face_num_Json = obj.value("face_num");
                qDebug() <<"face_num_Json="<< face_num_Json.toInt()<<"\n";
                if(face_num_Json.isDouble())
                {
                    face_num_val = face_num_Json.toInt();
                }
            }
            if(obj.contains("gender"))
            {
                QJsonValue gender_Json = obj.value("gender");
                if(gender_Json.isArray())
                {
                    QJsonArray gender_vals = gender_Json.toArray();
                    qDebug() <<"gender_vals="<< gender_vals<<"\n";
                    foreach (QJsonValue gval, gender_vals) {
                        if(gval.isDouble())
                            genders.push_back(gval.toInt()>0?true:false);
                    }
                    if(genders.size()!=face_num_val)
                    {
                        qDebug() << QString("gender vector num(%1) is not map face_num(%2)!")
                                    .arg(genders.size()).arg(face_num_val);
                    }

                }else{
                    qDebug() << "gender_Json value type is not map Array!";
                }
            }
            if(obj.contains("age"))
            {
                QJsonValue age_Json = obj.value("age");

                if(age_Json.isArray())
                {
                    QJsonArray age_vals = age_Json.toArray();
                    qDebug() <<"age_vals="<< age_vals<<"\n";
                    foreach (QJsonValue age_val, age_vals) {
                        if(age_val.isDouble())
                            ages.push_back(age_val.toInt());
                    }
                    if(ages.size()!=face_num_val)
                    {
                        qDebug() << QString("ages vector num(%1) is not map face_num(%2)!")
                                    .arg(ages.size()).arg(face_num_val);
                    }
                }else{
                    qDebug() << "age_Json value type is not map Array!";
                }
            }
            if(obj.contains("expression"))
            {
                QJsonValue expression_Json = obj.value("expression");
                if(expression_Json.isArray())
                {
                    QJsonArray expression_vals = expression_Json.toArray();
                    qDebug() <<"expression_vals="<< expression_vals<<"\n";
                    foreach (QJsonValue expression_val, expression_vals) {
                        if(expression_val.isDouble())
                            expressions.push_back(expression_val.toInt()>0?true:false);
                    }
                    if(expressions.size()!=face_num_val)
                    {
                        qDebug() << QString("expressions vector num(%1) is not map face_num(%2)!")
                                    .arg(expressions.size()).arg(face_num_val);
                    }
                }else{
                    qDebug() << "expression_Json value type is not map Array!";
                }
            }
            qDebug() << "face_num_val="<<face_num_val<<"\n"
                     << "genders="<<genders<<"\n"
                     << "ages="<<ages<<"\n"
                     << "expressions="<<expressions<<"\n";
        }
    }else{
        qDebug() << "QJsonDocument::fromJson fail:"<<json_error.errorString()<<"\n";
    }

下面给出本实例的完整通信接口供有需要的朋友,记得换成自己的key和密钥,由于是示例代码,很多地方未做优化和产品化考虑,请大家斟酌参考:

#ifndef FACEDETECTOBJECT_H
#define FACEDETECTOBJECT_H

#include <QObject>
#include <QString>
#include <QByteArray>
#include <QImage>

#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>

class FaceDetectObject
        : public QObject
{
    Q_OBJECT
public:
    FaceDetectObject(QObject * parent = 0);
    ~FaceDetectObject();

private:
    QByteArray getMD5(QByteArray bytes_);
    QByteArray HMACSha1(QByteArray key, QByteArray baseString);
    QByteArray  Image_To_Base64(QString image_path);
    QImage Base64_To_Image(QByteArray bytearray,QString save_Path);
    QByteArray  Image_To_ByteArray(QString image_path);
    QImage ByteArray_To_Image(QByteArray bytearray,QString save_Path);
public slots:
    void do_get();
    void do_post_img(QString imgFile);
    void do_post(QByteArray bytearray);
    void do_post_al(QByteArray bytearray);
private slots:
    void finishedReplay();
    void slotError(QNetworkReply::NetworkError net_error);
    void downloadProgress(qint64 bytesSent, qint64 bytesTotal);
private:
    QNetworkAccessManager *manager;
    QUrl url;
    QNetworkReply   *reply;
};

#endif // FACEDETECTOBJECT_H
#include "facedetectobject.h"

#include <QBuffer>
#include <QCryptographicHash>
#include <QDateTime>
#include <QFile>
#include <QSslConfiguration>
#include <QSslSocket>
#include <QDebug>

FaceDetectObject::FaceDetectObject(QObject * parent)
    : QObject(parent)
{
//    //test
//    QByteArray src = Image_To_ByteArray("fdtimg.jpg");
//    QImage dest = ByteArray_To_Image(src,"fdtimg_c.jpg");
    manager =new QNetworkAccessManager(this);
    url = QUrl("http://www.baidu.com/");
    reply = Q_NULLPTR;
}

FaceDetectObject::~FaceDetectObject()
{

}

void FaceDetectObject::do_get()
{
    QNetworkRequest request;
    request.setUrl(url);
    if(reply != Q_NULLPTR) {//更改reply指向位置钱一定要保证之前的定义了自动delete
        reply->deleteLater();
    }
    reply = manager->get(request);
//            connect(reply, &QNetworkReply::finished, this, &FaceDetectThread::finishedReplay);
    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)));
    qDebug() << "start get";
}

void FaceDetectObject::do_post_img(QString imgFile)
{
    qDebug()<<"do_post_img and imgfile="<<imgFile<<"\n";
    QByteArray imgByteArray = Image_To_Base64(imgFile);
    do_post_al(imgByteArray);
}

void FaceDetectObject::do_post(QByteArray bytearray)
{
    QNetworkRequest request;
    request.setUrl(url);
    request.setRawHeader("Content-Type","application/x-www-form-urlencoded");
    if(reply != Q_NULLPTR) {//更改reply指向位置钱一定要保证之前的定义了自动delete
        reply->deleteLater();
    }
    reply = manager->post(request,bytearray);
//            connect(reply, &QNetworkReply::finished, this, &FaceDetectThread::finishedReplay);
    connect(reply, SIGNAL(finished()), this, SLOT(finishedReplay()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
              this, SLOT(slotError(QNetworkReply::NetworkError)));
//            connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
//                      this, SLOT(slotSslErrors(QList<QSslError>)));
    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),
            this,SLOT(downloadProgress(qint64,qint64)));
    qDebug() << "start post";
}

void FaceDetectObject::do_post_al(QByteArray bytearray)
{
    qDebug()<<"img_bytearray_size="<<bytearray.size()<<"\n";
//    qDebug()<<"img_bytearray="<<bytearray.data()<<"\n";
    url = QUrl("https://dtplus-cn-shanghai.data.aliyuncs.com/face/attribute",QUrl::TolerantMode);
//    url.toEncoded();
    qDebug() <<"url="<<url.url()<<"\n";
    QString ak_id = "************";                     //key
    QString ak_secret = "*************************";    //secret
    /*
     * http header 参数
     */
    QString method = "POST";
    QString accept = "application/json";
    QString content_type = "application/json";
    QLocale lo = QLocale::English;//设置QLocale为英文
    QString date = lo.toString(QDateTime::currentDateTimeUtc(),"ddd, dd MMM yyyy hh:mm:ss")+QString(" GMT");
    qDebug() <<"date = " << date <<"\n";
    //1.对body做MD5+BASE64加密
    QByteArray body = QString("{\"type\":\"1\",\"content\":\"%1\"}").arg(bytearray.data()).toLocal8Bit();
    qDebug() <<"body = " << body <<"\n";
    QByteArray bodyMd5 = getMD5(body);
    qDebug() <<"bodyMd5 = " << bodyMd5 <<"\n";
    QString bodyBase64 = bodyMd5.toBase64();
    qDebug() <<"bodyBase64 = " << bodyBase64 <<"\n";
    QString stringToSign = method + "\n" + accept + "\n" + bodyBase64 + "\n" + content_type + "\n" + date + "\n"+ url.path();
    qDebug() << "stringToSign="<<stringToSign<<"\n";
    // 2.计算 HMAC-SHA1
    QString signature = HMACSha1(ak_secret.toLocal8Bit(),stringToSign.toLocal8Bit()).toBase64();
    qDebug() << "signature="<<signature<<"\n";
    // 3.得到 authorization header
    QString authHeader = "Dataplus " + ak_id + ":" + signature;
    qDebug() << "authHeader="<<authHeader<<"\n";
    QNetworkRequest request;
//    request.sslConfiguration().setPeerVerifyMode(QSslSocket::VerifyNone);
//    request.sslConfiguration().setProtocol(QSsl::TlsV1_0);

    QSslConfiguration config;
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    config.setProtocol(QSsl::TlsV1_0);
    request.setSslConfiguration(config);

    request.setUrl(url);
    request.setRawHeader(QByteArray("accept"), accept.toLocal8Bit());
    request.setHeader(QNetworkRequest::ContentTypeHeader,content_type);
    request.setRawHeader(QByteArray("date"), date.toLocal8Bit());
    request.setRawHeader(QByteArray("Authorization"), authHeader.toLocal8Bit());
//    request.setRawHeader(QByteArray("Connection"), QByteArray("keep-alive"));
    if(reply != Q_NULLPTR) {//更改reply指向位置钱一定要保证之前的定义了自动delete
        reply->deleteLater();
    }
    reply = manager->post(request,body);
//            connect(reply, &QNetworkReply::finished, this, &FaceDetectThread::finishedReplay);
    connect(reply, SIGNAL(finished()), this, SLOT(finishedReplay()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
              this, SLOT(slotError(QNetworkReply::NetworkError)));
//            connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
//                      this, SLOT(slotSslErrors(QList<QSslError>)));
    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),
            this,SLOT(downloadProgress(qint64,qint64)));
    qDebug() << "start post_al";
}

QByteArray FaceDetectObject::getMD5(QByteArray bytes_)
{
    QCryptographicHash ch(QCryptographicHash::Md5);
    QByteArray ret;
    ch.addData(bytes_);
    ret = ch.result();
    return ret;
}

QByteArray FaceDetectObject::HMACSha1(QByteArray key, QByteArray baseString)
 {
     int blockSize = 64;                // HMAC-SHA-1 block size, defined in SHA-1 standard
     if (key.length() > blockSize) {    // if key is longer than block size (64), reduce key length with SHA-1 compression
         key = QCryptographicHash::hash(key, QCryptographicHash::Sha1);
     }
     QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"
     QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "/"
     // ascii characters 0x36 ("6") and 0x5c ("/") are selected because they have large
     // Hamming distance (http://en.wikipedia.org/wiki/Hamming_distance)
     for (int i = 0; i < key.length(); i++) {
         innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key length
         outerPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length
     }
     // result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64
     QByteArray total = outerPadding;
     QByteArray part = innerPadding;
     part.append(baseString);
     total.append(QCryptographicHash::hash(part, QCryptographicHash::Sha1));
     QByteArray hashed = QCryptographicHash::hash(total, QCryptographicHash::Sha1);
          /// 注意——>把字符串hashed转换为Hex,内存中的ASCII码arrayFromHexString
     QByteArray arrayFromHexString = QByteArray::fromHex(hashed.toHex());
     qDebug()<<"hmacSha1内存中的ASCII码 arrayFromHexString \n"<<arrayFromHexString.toHex();
     return arrayFromHexString;
}

QByteArray  FaceDetectObject::Image_To_Base64(QString image_path)
{
    QImage image(image_path);
    QByteArray ba;
    QBuffer buf(&ba);
    image.save(&buf,"jpg");
    QByteArray hexed = ba.toBase64();
    buf.close();
    return hexed;
}

QImage FaceDetectObject::Base64_To_Image(QByteArray bytearray,QString save_Path)
{
    QByteArray Ret_bytearray;
    Ret_bytearray = QByteArray::fromBase64(bytearray);
    QBuffer buffer(&Ret_bytearray);
    buffer.open(QIODevice::WriteOnly);
    QImage imageresult;
    imageresult.loadFromData(Ret_bytearray);
    if(save_Path != "")
    {
        qDebug() <<"save" ;
        imageresult.save(save_Path);
    }
    return imageresult;
}

QByteArray  FaceDetectObject::Image_To_ByteArray(QString image_path)
{
    qDebug()<<"image_path="<<image_path<<"\n";
    QImage image(image_path);
    QByteArray ba;
    QBuffer buf(&ba);
    image.save(&buf,"jpg");
    qDebug()<<"ba_size="<<ba.size()<<"\n";
//    qDebug()<<"ba="<<ba.data()<<"\n";
    buf.close();
    return ba;
}

QImage FaceDetectObject::ByteArray_To_Image(QByteArray bytearray,QString save_Path)
{
    QBuffer buffer(&bytearray);
    buffer.open(QIODevice::WriteOnly);
    QImage imageresult;
    imageresult.loadFromData(bytearray);
    if(save_Path != "")
    {
        qDebug() <<"save" ;
        imageresult.save(save_Path);
    }
    return imageresult;
}

void FaceDetectObject::finishedReplay()
{
    QByteArray bytes = reply->readAll();
    const QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
    reply->deleteLater();
    reply = Q_NULLPTR;
    if (!redirectionTarget.isNull()) {//如果网址跳转重新请求
        const QUrl redirectedUrl = url.resolved(redirectionTarget.toUrl());
        qDebug()<<"redirectedUrl:"<<redirectedUrl.url()<<"\n";
        url = redirectedUrl;
        qDebug()<<"new_url="<<url.toString().toLocal8Bit()<<"\n";
        //写出新url,测试使用
        QFile f("url_.txt");//写出文件
        f.open(QFile::WriteOnly);
        f.write(url.toString().toLocal8Bit());
        f.close();
        return;
    }
    qDebug()<<"finished:\n";
    QString  html_text = bytes;
    qDebug()<<"get ready,read size:"<<html_text.size();
    qDebug()<< "ret_html_text:\n"<<html_text<<"\n";
    //保存结果,测试使用
    QFile f("result.html");//写出文件
    f.open(QFile::WriteOnly);
    f.write(bytes);
    f.close();
}

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

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

 

目录
相关文章
|
6月前
|
开发框架 Linux C语言
C、C++、boost、Qt在嵌入式系统开发中的使用
C、C++、boost、Qt在嵌入式系统开发中的使用
214 1
|
4月前
|
数据安全/隐私保护 C++ 计算机视觉
Qt(C++)开发一款图片防盗用水印制作小工具
文本水印是一种常用的防盗用手段,可以将文本信息嵌入到图片、视频等文件中,用于识别和证明文件的版权归属。在数字化和网络化的时代,大量的原创作品容易被不法分子盗用或侵犯版权,因此加入文本水印成为了保护原创作品和维护知识产权的必要手段。 通常情况下,文本水印可以包含版权声明、制作者姓名、日期、网址等信息,以帮助识别文件的来源和版权归属。同时,为了增强防盗用效果,文本水印通常会采用字体、颜色、角度等多种组合方式,使得水印难以被删除或篡改,有效地降低了盗用意愿和风险。 开发人员可以使用图像处理技术和编程语言实现文本水印的功能,例如使用Qt的QPainter类进行文本绘制操作,将文本信息嵌入到图片中,
181 1
Qt(C++)开发一款图片防盗用水印制作小工具
WK
|
13天前
|
开发框架 开发工具 C++
C++跨平台框架Qt
Qt是一个功能强大的C++跨平台应用程序开发框架,支持Windows、macOS、Linux、Android和iOS等操作系统。它提供了250多个C++类,涵盖GUI设计、数据库操作、网络编程等功能。Qt的核心特点是跨平台性、丰富的类库、信号与槽机制,以及良好的文档和社区支持。Qt Creator是其官方IDE,提供了一整套开发工具,方便创建、编译、调试和运行应用程序。Qt适用于桌面、嵌入式和移动应用开发。
WK
48 5
|
5月前
|
文字识别 算法 API
视觉智能开放平台产品使用合集之uniapp框架如何使用阿里云金融级人脸识别
视觉智能开放平台是指提供一系列基于视觉识别技术的API和服务的平台,这些服务通常包括图像识别、人脸识别、物体检测、文字识别、场景理解等。企业或开发者可以通过调用这些API,快速将视觉智能功能集成到自己的应用或服务中,而无需从零开始研发相关算法和技术。以下是一些常见的视觉智能开放平台产品及其应用场景的概览。
137 0
|
3月前
|
存储 C++
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】
|
3月前
|
C++
C++ Qt开发:QUdpSocket网络通信组件
QUdpSocket是Qt网络编程中一个非常有用的组件,它提供了在UDP协议下进行数据发送和接收的能力。通过简单的方法和信号,可以轻松实现基于UDP的网络通信。不过,需要注意的是,UDP协议本身不保证数据的可靠传输,因此在使用QUdpSocket时,可能需要在应用层实现一些机制来保证数据的完整性和顺序,或者选择在适用的场景下使用UDP协议。
158 2
|
3月前
|
存储 算法 C++
【C++】C++ QT实现Huffman编码器与解码器(源码+课程论文+文件)【独一无二】
【C++】C++ QT实现Huffman编码器与解码器(源码+课程论文+文件)【独一无二】
|
3月前
|
安全 C++
C++ QT 单例模式
C++ QT 单例模式
55 0
|
4月前
|
数据可视化 开发者 C++
Qt(C++)使用QChart静态显示3个设备的温度变化曲线
QChart模块是Qt Charts库的基础,提供了用于创建和显示各种类型图表的类和接口。Qt Charts库是一个功能丰富、易于使用的数据可视化工具库,可以帮助开发者在应用程序中添加漂亮而又交互性强的图表。
71 1
Qt(C++)使用QChart静态显示3个设备的温度变化曲线
|
3月前
|
安全 C++ Windows
Windows下C++使用gRPC(Qt和VS,含文件包和使用方法)
Windows下C++使用gRPC(Qt和VS,含文件包和使用方法)

热门文章

最新文章

下一篇
无影云桌面