首先需要明白人脸、人脸集合(faceset)、人脸比对、人脸搜索的概念,以及如何调用face++接口。本文使用的是qt平台、语言C++。可以参考文章:人脸识别——Qt通过发起Http请求调用face++接口
下面是具体过程
- 创建人脸集合faceSet。使用此接口
https://api-cn.faceplusplus.com/facepp/v3/faceset/create - 进行人脸检测,将图片转换为face_token。(face_token是图片的标识)调用此接口
https://api-cn.faceplusplus.com/facepp/v3/detect - 将获得的face_token加入人脸集合faceSet。(图片每次检测获得face_token都不同,如果一定时间内没有加入faceSet,那么这个face_token将会失效,所以需要检测后加入faceSet)。加入faceSet调用此接口
https://api-cn.faceplusplus.com/facepp/v3/faceset/addface - 将face_token与真实的人的信息建立起映射关系。因为调用搜索API返回的是图片的face_token。我们肯定希望知道face_token对应的图片是谁.
- 进行人脸搜索,将会返回faceSet中人脸相似度最高的face-token。调用此接口
https://api-cn.faceplusplus.com/facepp/v3/search
具体代码如下:
头文件:
#ifndef FACE_H
#define FACE_H
#include <cstdio>
#include <QString>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include<opencv2/cxcore.h>
#include <QFile>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QHttpPart>
#include <QEventLoop>
#include <QTimer>
#include <QObject>
#include <stdio.h>
#include <QString>
#include "dbpostgis.h"
#include <QHttpMultiPart>
#include <QHttpPart>
#include <QPushButton>
#include <QLabel>
#include <string>
#include <vector>
#include <QFile>
#include <opencv/cv.h>
using namespace cv;
using namespace std;
class Face : public QObject
{
Q_OBJECT
public:
Face();
void test()
void detectAndDisplay(QString filePath,Mat frame);
int connetNetWork(); //连接网络 使用face++ 否则使用openCV
QHttpPart setHttpPart(QByteArray body,QVariant value);//used in face++ to set params
QHttpPart imageHttpPart(const QString &filename,QVariant value);//used in face++ to set params
QHttpMultiPart* setKeyAndSecret();
void createFaceSet(QString displayName,QString outerId);
QList<QString> getfaceToken(QByteArray responseData);
void detectFace(const QString &filename);
void addFaceTokens(QList<QString>faceTokens);
//将两个人脸进行比对,来判断是否为同一个人,返回比对结果置信度和不同误识率下的阈值。
void compareFace(const QString &faceTk1,const QString &faceTk2);
//在已有的 FaceSet 中找出与目标人脸最相似的一张或多张人脸,返回置信度和不同误识率下的阈值。
void searchFace(const QString &image);
public slots:
void finishedQ(QNetworkReply *reply);
void finishedDetect(QNetworkReply *reply);
void finishedSearch(QNetworkReply *reply);
public:
bool getIsError() const;
void setIsError(bool value);
private:
QNetworkAccessManager *manager;
QString filename1;
QString filename2;
QString apiKey,apiSecret;
QString faceset_token,outer_id;
bool isError= false;
double confidence;// searchApi 中得出的confidence
QString face_token;//在faceSet中找出的和目标人脸最相思的人脸的face_token
};
#endif // FACE_H
Face::Face()
{
//改成自己的图片路径
filename1 = "E:\\photo\\photoManagement2\\test.jpg";
filename2 = "E:\\photo\\photoManagement2\\test3.jpg";
//followings are some keys used in face++ which cann't be modified
this->apiKey = "api_key";// 改成自己的apikey和apisecret
this->apiSecret = "api_secret";
this->faceset_token ="xxx";//当创建好faceset集合后改为自己的faceset_token
this->outer_id ="facesInPhotoManagement";
confidence = 0.0;
face_token = "";
}
//this function used as entry point for image recognition
void Face::test()
{
QList<QString>filenames;
filenames.push_back(filename1);
filenames.push_back(filename2);
detectFace(filenames);
qDebug()<<("Hello Open CV!");
//改为自己的图片路径
QString filepath="E:/photo/photoManagement/hezhao1.jpg";
connetNetWork();
}
int Face::connetNetWork(){
QNetworkAccessManager netAccMana;
QString urlString = "https://www.faceplusplus.com.cn/";
QUrl url(urlString + "user/get");
qDebug() <<url<<'\n';
QNetworkRequest request(url); // use url to build a request object
request.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json;charset=utf-8")); // set request header
QTimer timer;
timer.setInterval(8000); // 设置超时时间 8 秒
timer.setSingleShot(true); // 单次触发
QNetworkReply *pReply = netAccMana.get(request);
QEventLoop loop;
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
connect(pReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
timer.start();
loop.exec(); //loop循环
if (timer.isActive()){
timer.stop();//此时 QNetworkReply::finished,响应完成,还尚未超时
if (pReply->error() != QNetworkReply::NoError) {
qDebug() << "the error is"<<pReply->error()<<" ,使用openCV : ";
return 0;
}else {
qDebug() << "联网测试成功,使用face++ : ";
}
}else { //超过5秒
disconnect(pReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
pReply->abort();
pReply->deleteLater();
qDebug() << "使用openCV : ";
}
return 1;
}
QHttpPart Face::setHttpPart(QByteArray body, QVariant value)
{
QHttpPart part ;
part.setHeader(QNetworkRequest::ContentDispositionHeader,value);
part.setBody(body);
return part;
}
QHttpPart Face::imageHttpPart(const QString &filename, QVariant value)
{
QHttpPart imagePart ;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("image/jpeg"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader,value);
QImage image(filename);
QByteArray ba;
QByteArray hex;
QBuffer buf(&ba);
if(buf.open(QIODevice::WriteOnly)){
image.save(&buf,"jpeg",20);
hex = ba.toBase64();
buf.close();
}else{
qDebug()<<"buf.error"<<buf.errorString();
}
imagePart.setBody(hex);
return imagePart;
}
void Face::createFaceSet(QString displayName, QString outerId)
{ QTimer timer;
timer.setInterval(8000);
timer.setSingleShot(true);
QNetworkAccessManager *manager = new QNetworkAccessManager;
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart apikey = setHttpPart(this->apiKey.toLatin1(),QVariant("form-data; name=\"api_key\""));
QHttpPart apisecret = setHttpPart(this->apiSecret.toLatin1(),QVariant("form-data; name=\"api_secret\""));
multiPart->append(apikey);
multiPart->append(apisecret);
if(displayName!=""){
QHttpPart textPart1;
textPart1 = setHttpPart(displayName.toLatin1(),QVariant("form-data;name=\"display_name\""));
multiPart->append(textPart1);
}
if(outerId!=""){
QHttpPart textPart2;
textPart2 = setHttpPart(outerId.toLatin1(),QVariant("form-data;name=\"outer_id\""));
multiPart->append(textPart2);
}
QUrl url("https://api-cn.faceplusplus.com/facepp/v3/faceset/create");
QNetworkRequest request(url);
QNetworkReply *reply = manager->post(request, multiPart);
QEventLoop loop;
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
timer.start();
loop.exec();
if (timer.isActive()){
timer.stop();
if (reply->error() != QNetworkReply::NoError) {
this->isError = true;
qDebug() << "In faceSetCreate the error is "<<reply->errorString();
return ;
}else {
this->isError = false;
qDebug()<<reply->readAll();
}
}else { //超过8秒
disconnect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
reply->abort();
reply->deleteLater();
qDebug() << "联网超时";
}
}
QList<QString> Face::getfaceToken(QByteArray responseData)
{
QMap<QString,QVariant>map;
QJsonDocument documment ;
map = documment.fromJson(responseData).toVariant().toMap();
if(isError){
QString errorMsg = map.value("error_message").toString();
QList<QString>errors;
errors.push_back(errorMsg);
return errors;
}else{
QJsonArray faces = map.value("faces").toJsonArray();
QList<QString> faceTokens;
for(int i = 0;i<faces.size();i++){
QJsonObject faceObj =faces.at(i).toObject();
QString faceToken = faceObj.value("face_token").toString();
faceTokens.push_back(faceToken);
}
return faceTokens;
}
}
void Face::detectFace(const QString &filename)
{
QTimer timer;
timer.setInterval(10000);
timer.setSingleShot(true);
QNetworkAccessManager *manager = new QNetworkAccessManager;
if(filename!=""){
QUrl url("https://api-cn.faceplusplus.com/facepp/v3/detect");
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart apikey = setHttpPart(this->apiKey.toLatin1(),QVariant("form-data; name=\"api_key\""));
QHttpPart apisecret = setHttpPart(this->apiSecret.toLatin1(),QVariant("form-data; name=\"api_secret\""));
multiPart->append(apikey);
multiPart->append(apisecret);
QString dataform = "form-data; name=\"image_base64\"";
QHttpPart imagePart = imageHttpPart(filename.toLatin1(),dataform);
multiPart->append(imagePart);
QNetworkRequest request(url);
QNetworkReply *reply = manager->post(request, multiPart);
multiPart->setParent(reply); // 用 reply 删除 multiPart
QEventLoop loop;
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
timer.start();
loop.exec(); //loop循环
if (timer.isActive()){
//此时 QNetworkReply::finished,响应完成,还尚未超时
timer.stop();
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (reply->error() != QNetworkReply::NoError) {
this->isError=true;
qDebug() << "In detectImage the error is "<<reply->error()<<reply->errorString();
return ;
}else {
finishedDetect(reply);
this->isError = false;
}
}else { //超过8秒
disconnect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
reply->abort();
reply->deleteLater();
qDebug() << "联网超时";
}
}
}
void Face::addFaceTokens(QList<QString> faceTokens)
{
QTimer timer;
timer.setInterval(8000);
timer.setSingleShot(true);
QNetworkAccessManager *manager = new QNetworkAccessManager;
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart apikey,apisecret,faceset_token,face_tokens;
apikey = setHttpPart(this->apiKey.toLatin1(),QVariant("form-data; name=\"api_key\""));
apisecret = setHttpPart(this->apiSecret.toLatin1(),QVariant("form-data; name=\"api_secret\""));
faceset_token = setHttpPart(this->faceset_token.toLatin1(),QVariant("form-data; name=\"faceset_token\""));
QString facetokenStr="";
if(faceTokens.size()<1){
return ;
}
for(int i = 0;i<faceTokens.size()-1;i++){
facetokenStr=facetokenStr+faceTokens[i]+",";
}
facetokenStr = facetokenStr+faceTokens[faceTokens.size()-1];
qDebug()<<"查看facetokemmstr"<<facetokenStr;
face_tokens = setHttpPart(facetokenStr.toLatin1(),QVariant("form-data; name=\"face_tokens\""));
multiPart->append(apikey);
multiPart->append(apisecret);
multiPart->append(faceset_token);
multiPart->append(face_tokens);
QUrl url("https://api-cn.faceplusplus.com/facepp/v3/faceset/addface");
QNetworkRequest request(url);
QNetworkReply *reply = manager->post(request,multiPart);
multiPart->setParent(reply); // 用 reply 删除 multiPart
QEventLoop loop;
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
timer.start();
loop.exec(); //loop循环
if (timer.isActive()){
//此时 QNetworkReply::finished,响应完成,还尚未超时
timer.stop();
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug()<<"httpCodes"<<statusCode;
if (reply->error() != QNetworkReply::NoError) {
this->isError=true;
qDebug() << "In addFaceToken the error is "<<reply->error()<<reply->errorString();
return ;
}else {
qDebug()<<reply->readAll();
}
}else { //超过8秒
disconnect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
reply->abort();
reply->deleteLater();
qDebug() << "联网超时";
}
if(reply->error()==QNetworkReply::NoError){
qDebug()<<"测试加入facetoken"<<reply->readAll();
}else{
qDebug()<<"error in AddFaceToken "<<reply->errorString();
}
}
void Face::compareFace(const QString &faceTk1, const QString &faceTk2)
{
QTimer timer;
timer.setInterval(8000);
timer.setSingleShot(true);
QNetworkAccessManager *manager = new QNetworkAccessManager;
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart apikey,apisecret,face1,face2;
apikey = setHttpPart(this->apiKey.toLatin1(),QVariant("form-data; name=\"api_key\""));
apisecret = setHttpPart(this->apiSecret.toLatin1(),QVariant("form-data; name=\"api_secret\""));
face1 = imageHttpPart(faceTk1.toLatin1(),QVariant("form-data; name=\"image_base64_1\""));
face2 = imageHttpPart(faceTk2.toLatin1(),QVariant("form-data; name=\"image_base64_2\""));
multiPart->append(apikey);
multiPart->append(apisecret);
multiPart->append(face1);
multiPart->append(face2);
QUrl url("https://api-cn.faceplusplus.com/facepp/v3/compare");
QNetworkRequest request(url);
QNetworkReply *reply = manager->post(request,multiPart);
multiPart->setParent(reply);
QEventLoop loop;
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
timer.start();
loop.exec(); //loop循环
if (timer.isActive()){
//此时 QNetworkReply::finished,响应完成,还尚未超时
timer.stop();
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug()<<"httpCodes"<<statusCode;
if (reply->error() != QNetworkReply::NoError) {
this->isError=true;
qDebug() << "In compareFace the error is "<<reply->error()<<reply->errorString();
return ;
}else {
isError= false;
finishedSearch(reply);
}
}else { //超过8秒
disconnect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
reply->abort();
reply->deleteLater();
qDebug() << "联网超时";
}
}
void Face::searchFace(const QString &image)
{
QTimer timer;
timer.setInterval(8000);
timer.setSingleShot(true);
QNetworkAccessManager *manager = new QNetworkAccessManager;
connect(manager,&QNetworkAccessManager::finished,this,&Face::finishedSearch);
QHttpMultiPart * multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart apikey,apisecret,targetImg,faceset;
apikey = setHttpPart(this->apiKey.toLatin1(),QVariant("form-data; name=\"api_key\""));
apisecret = setHttpPart(this->apiSecret.toLatin1(),QVariant("form-data'; name=\"api_secret\""));
targetImg = setHttpPart(image.toLatin1(),QVariant("form-data; name=\"face_token\""));
faceset = setHttpPart(this->faceset_token.toLatin1(),QVariant("form-data; name=\"faceset_token\""));
multiPart->append(apikey);
multiPart->append(apisecret);
multiPart->append(targetImg);
multiPart->append(faceset);
QUrl url("https://api-cn.faceplusplus.com/facepp/v3/search");
QNetworkRequest request(url);
QNetworkReply *reply = manager->post(request,multiPart);
multiPart->setParent(reply);
QEventLoop loop;
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
timer.start();
loop.exec(); //loop循环
if (timer.isActive()){
//此时 QNetworkReply::finished,响应完成,还尚未超时
timer.stop();
if (reply->error() != QNetworkReply::NoError) {
this->isError=true;
qDebug() << "In searchFace the error is "<<reply->error()<<reply->errorString();
return ;
}else {
this->isError= false;
// finishedSearch(reply);
}
}else { //超过8秒
disconnect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
reply->abort();
reply->deleteLater();
qDebug() << "联网超时";
}
}
````void Face::finishedQ(QNetworkReply *reply)
{
int error = reply->error();
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug()<<"httpCodes"<<statusCode;
if(error==QNetworkReply::NoError && statusCode==200){
QByteArray responseData = reply->readAll();
QList<QString>faceTokens;
faceTokens = getfaceToken(responseData);
qDebug()<<"dajdadjadada"<<responseData<<" "<<faceTokens;
if(faceTokens.size()>0){
addFaceTokens(faceTokens);
}
QMap<QString,QVariant>map;
QJsonDocument documment ;
map = documment.fromJson(responseData).toVariant().toMap();
qDebug()<<"responese data:"<<responseData;
float confidence = map.value("confidence").toFloat();
qDebug()<<"the confidence is "<<confidence;
}else{
qDebug()<<"In finishedQ the error is "<<error<<reply->errorString();
}
}
void Face::finishedDetect(QNetworkReply *reply)
{
if(!isError){
QByteArray responseData = reply->readAll();
qDebug()<<"responseData"<<responseData;
QList<QString>faceTokens;
faceTokens = getfaceToken(responseData);
if(faceTokens.size()>0){
for(int i = 0;i<faceTokens.size();i++){
qDebug()<<"in finishedDetect :"<<faceTokens[i];
searchFace(faceTokens[i]);
if(this->confidence>=80.000){
qDebug()<<"faceSet已有此人,不将此人脸入库";
}else{
qDebug()<<"加入数据库,关联相关信息";
}
}
addFaceTokens(faceTokens);
}
}
}
void Face::finishedSearch(QNetworkReply *reply)
{
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug()<<"httpCodes"<<statusCode;
qDebug()<<"In finishedSearch :"<<reply->readAll();
if(reply->error()==QNetworkReply::NoError && statusCode==200){
QByteArray responseData = reply->readAll();
QMap<QString,QVariant>map;
QJsonDocument documment ;
map = documment.fromJson(responseData).toVariant().toMap();
double confidence = 0.0;
QString face_token;
QJsonArray results = map.value("results").toJsonArray();
if(!results.isEmpty()){
QJsonObject obj = results[0].toObject();
confidence = obj.value("confidence").toDouble();
face_token = obj.value("face_token").toString();
qDebug()<<map.value("thresholds").toJsonArray()<<"\n"<<map.value("results").toJsonArray();
}
setMaxConfidence(face_token,confidence);
qDebug()<<map.value("thresholds").toJsonArray()<<"\n"<<map.value("results").toJsonArray();
}else{
qDebug()<<"faceSearch error is "<<reply->errorString();
}
}
欢迎大家 批评指教!~~~