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;
}

 

目录
相关文章
|
1月前
|
安全 前端开发 C++
C++视角下的Qt按钮:从基础应用到高级定制(二)
C++视角下的Qt按钮:从基础应用到高级定制
45 2
|
1月前
|
XML JSON 算法
C++视角下的Qt按钮:从基础应用到高级定制(一)
C++视角下的Qt按钮:从基础应用到高级定制
90 2
|
1月前
|
XML 安全 C++
DBus类型系统以及在Qt和C++ 中的使用(二)
DBus类型系统以及在Qt和C++ 中的使用
44 0
|
1月前
|
XML 存储 Unix
DBus类型系统以及在Qt和C++ 中的使用(一)
DBus类型系统以及在Qt和C++ 中的使用
41 0
|
1月前
|
存储 开发框架 开发者
QT C++焦点事件:多角度解析实用技巧与方法
QT C++焦点事件:多角度解析实用技巧与方法
149 0
|
1月前
|
网络协议 C++
C++ Qt开发:QTcpSocket网络通信组件
`QTcpSocket`和`QTcpServer`是Qt中用于实现基于TCP(Transmission Control Protocol)通信的两个关键类。TCP是一种面向连接的协议,它提供可靠的、双向的、面向字节流的通信。这两个类允许Qt应用程序在网络上建立客户端和服务器之间的连接。Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QTcpSocket`组件实现基于TCP的网络通信功能。
38 8
C++ Qt开发:QTcpSocket网络通信组件
|
29天前
|
编译器 API 数据安全/隐私保护
深入对比:Qt 的 QFile/QFileInfo 和与 C++17 Filesystem 和标准文件流 的细节剖析
深入对比:Qt 的 QFile/QFileInfo 和与 C++17 Filesystem 和标准文件流 的细节剖析
99 3
|
1月前
|
SQL XML API
Qt C++ 模块 描述列表【从Qt 官网 6.5 版本翻译】
Qt C++ 模块 描述列表【从Qt 官网 6.5 版本翻译】
13 0
|
1月前
|
设计模式 安全 API
C++视角下的Qt按钮:从基础应用到高级定制(三)
C++视角下的Qt按钮:从基础应用到高级定制
52 0
|
1月前
使用阿里云智能翻译接口案例—
使用阿里云智能翻译接口案例—
11 0

热门文章

最新文章

推荐镜像

更多