百度AI——人脸识别的简单应用
程序员文章站
2023-12-21 19:59:40
...
因为工作上的需要,最近接触到百度的AI开放平台,应用到了它上面的人脸对比功能。因为百度AI的接口开放的时间不久,使用的人不是很多,这里就百度给的API及其应用做个简单的介绍。百度的说明文档,可以在这里查看http://ai.baidu.com/docs#/Begin/top
应为我使用的是C++编码,百度没有提供相应的SDK。所以就直接调用API了。
首先环境搭建,因为要使用https协议,所以需要依赖于OpenSSL和curl 两个库,解析返回参数的时候还需要json库。
我使用的是Ubuntu16.04 linux环境,依赖库的安装就不介绍了,直接上代码。
首先按照百度的说明,创建用户,创建工程。然后需要自己编码获取自己的AccessKey。我创建了一个测试工程,获取AccessKey的代码如下:
#include <iostream>
#include <string>
#include "include/curl.h"
#include "include/json.h"
using namespace std;
//#include "access_token.h"
// libcurl库下载链接:https://curl.haxx.se/download.html
// jsoncpp库下载链接:https://github.com/open-source-parsers/jsoncpp/
// 获取access_token所需要的url
const std::string access_token_url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials";
// 回调函数获取到的access_token存放变量
// static std::string access_token_result;
/**
* curl发送http请求调用的回调函数,回调函数中对返回的json格式的body进行了解析,解析结果储存在result中
* @param 参数定义见libcurl库文档
* @return 返回值定义见libcurl库文档
*/
static size_t callback(void *ptr, size_t size, size_t nmemb, void *stream) {
// 获取到的body存放在ptr中,先将其转换为string格式
std::string s((char *) ptr, size * nmemb);
// 开始获取json中的access token项目
Json::Reader reader;
Json::Value root;
// 使用boost库解析json
reader.parse(s,root);
std::string* access_token_result = static_cast<std::string*>(stream);
*access_token_result = root["access_token"].asString();
return size * nmemb;
}
/**
* 用以获取access_token的函数,使用时需要先在百度云控制台申请相应功能的应用,获得对应的API Key和Secret Key
* @param access_token 获取得到的access token,调用函数时需传入该参数
* @param AK 应用的API key
* @param SK 应用的Secret key
* @return 返回0代表获取access token成功,其他返回值代表获取失败
*/
int get_access_token(std::string &access_token, const std::string &AK, const std::string &SK) {
CURL *curl;
CURLcode result_code;
int error_code = 0;
curl = curl_easy_init();
if (curl) {
std::string url = access_token_url + "&client_id=" + AK + "&client_secret=" + SK;
curl_easy_setopt(curl, CURLOPT_URL, url.data());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
std::string access_token_result;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &access_token_result);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
result_code = curl_easy_perform(curl);
if (result_code != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(result_code));
return 1;
}
access_token = access_token_result;
curl_easy_cleanup(curl);
error_code = 0;
} else {
fprintf(stderr, "curl_easy_init() failed.");
error_code = 1;
}
return error_code;
}
int main(void)
{
int ret = -1;
std::string APIKey ="6o7WPmwKjVBk7Bz80gbWgz1T";
std::string SecretKey = "ypBbZsfyGnoT7aC5iUqPcA6kQk1wCBV0";
std::string AccessKey;
ret = get_access_token(AccessKey, APIKey, SecretKey);
cout<<"ret="<<ret<<endl;
cout<<"SecretKey:"<<SecretKey<<endl;
cout<<"AccessKey:"<<AccessKey<<endl;
return 0;
}
运行结果如下:
aaa@qq.com:~/face_example$ ./test
ret=0
SecretKey:ypBbZsfyGnoT7aC5iUqPcA6kQk1wCBV0
AccessKey:24.aeb0199102972324f40e88bf7ee70228.2592000.1505703119.282335-9971270
aaa@qq.com:~/face_example$
AccessKey 就是我们后面在做人脸识别的时候需要的一个key,将这个AccessKey 应用到人脸对比的应用中。代码如下:
#include <iostream>
#include <vector>
#include <string>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include "include/curl.h"
#include "include/json.h"
using namespace std;
#define PATH_LEN 50
const std::string AccessKey ="24.ffa72141704d37766446011d4a595083.2592000.1504770959.282335-9983145";
static const char* base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const static std::string face_match_url = "https://aip.baidubce.com/rest/2.0/face/v2/match";
static std::string face_match_result;
/**
* curl发送http请求调用的回调函数,回调函数中对返回的json格式的body进行了解析,解析结果储存在全局的静态变量当中
* @param 参数定义见libcurl文档
* @return 返回值定义见libcurl文档
*/
static size_t callback(void *ptr, size_t size, size_t nmemb, void *stream) {
// 获取到的body存放在ptr中,先将其转换为string格式
cout << "into callback"<<endl;
face_match_result = std::string((char *) ptr, size * nmemb);
return size * nmemb;
}
/**
* 调用人脸匹配接口,返回json格式的结果,具体格式解析见百度大脑文档
* @param json_result 以string格式返回的json格式的结果
* @param images 多个base64编码的图像数据字符串 注:base64数据不包含格式信息(即不包含data:image/jpeg;base64))
* @param access_token 以string格式传入的access token数据,access token获取方式见access_token获取相关文档及代码
* @return 调用成功返回0,发生错误返回其他错误码
*/
int match(std::string &json_result, const std::vector<std::string> &images, const std::string &access_token) {
std::string url = face_match_url + "?access_token=" + access_token;
CURL *curl = NULL;
CURLcode result_code;
int is_success;
double start,end,cost;
start=clock();
curl = curl_easy_init();
if (curl) {
std::string image_plain = images[0];
for (int i = 1; i < images.size(); i++) {
image_plain.append("," + images[i]);
}
curl_easy_setopt(curl, CURLOPT_URL, url.data());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_httppost *post = NULL;
curl_httppost *last = NULL;
curl_formadd(&post, &last, CURLFORM_COPYNAME, "images", CURLFORM_COPYCONTENTS, image_plain.data(),
CURLFORM_END);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
result_code = curl_easy_perform(curl);
if (result_code != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(result_code));
is_success = 1;
return is_success;
}
cout<<"result_code=" <<result_code<<endl;
json_result = face_match_result;
curl_easy_cleanup(curl);
is_success = 0;
} else {
fprintf(stderr, "curl_easy_init() failed.");
is_success = 1;
}
return is_success;
}
int Read_Image(char *path, char* out)
{
FILE *fd;
int length;
int ret;
fd = fopen(path,"r");
if(fd==NULL)
{
cout<<"Read_Image open file err"<<endl;
}
fseek(fd, 0, SEEK_END);
length = ftell(fd);
fseek(fd, 0, SEEK_SET);
ret = fread(out, 1, length, fd);
if(ret == 0)
{
cout<<"Read_Image fread err" <<endl;
}
fclose(fd);
return ret;
}
//chsrc为源数据,chdes为Base64编码后的数据,len为数据长度
void Base64_Code(char* chsrc, char* chdes, int len)
{
unsigned char char_array_3[3], char_array_4[4];
int i = 0, j = 0;
while(len--)
{
char_array_3[i++] = *(chsrc++);
if(3 == i)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; i < 4; i++)
*(chdes+i) = base64_chars[char_array_4[i]];
i = 0;
chdes += 4;
}
}
if(i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(j = 0; j < (i+1); j++)
*(chdes++) = base64_chars[char_array_4[j]];
while((3 > i++))
*(chdes++) = '=';
}
*chdes = '\0';
return;
}
int Calculat_FlieLength(char *path)
{
FILE *fd;
int length;
fd = fopen(path,"r");
fseek(fd, 0, SEEK_END);
length = ftell(fd);
fseek(fd, 0, SEEK_SET);
fclose(fd);
return length;
}
int ReadJson_Int(const std::string & strValue, std::string key, int &value)
{
Json::Reader reader;
Json::Value root;
int ret = -1;
if (reader.parse(strValue, root))
{
value = root[key].asInt();
ret = 0;
}else
{
ret = -1;
}
return ret;
}
int ReadJson_Long(const std::string & strValue, std::string key, long &value)
{
Json::Reader reader;
Json::Value root;
int ret = -1;
if (reader.parse(strValue, root))
{
value = root[key].asDouble();
ret = 0;
}else
{
ret = -1;
}
return ret;
}
int ReadJson_string(const std::string & strValue, std::string key, std::string &value)
{
Json::Reader reader;
Json::Value root;
int ret = -1;
if (reader.parse(strValue, root))
{
value = root[key].asString();
ret = 0;
}
return ret;
}
int ReadJson_arrayObj_int(const std::string & strValue, std::string obj, std::string key, int &value)
{
Json::Reader reader;
Json::Value root;
int ret = -1;
if (reader.parse(strValue, root))
{
Json::Value arrayObj = root[obj];
for(unsigned int i = 0; i < arrayObj.size(); i++)
{
if (arrayObj[i].isMember(key))
{
value = arrayObj[i][key].asInt();
ret = 0;
}else
{
ret = -1;
}
}
}
return ret;
}
int ReadJson_arrayObj_string(const std::string & strValue, std::string obj, std::string key, std::string &value)
{
Json::Reader reader;
Json::Value root;
int ret = -1;
if (reader.parse(strValue, root))
{
Json::Value arrayObj = root[obj];
for(unsigned int i = 0; i < arrayObj.size(); i++)
{
if (arrayObj[i].isMember(key))
{
value = arrayObj[i][key].asString();
ret = 0;
}else
{
ret = -1;
}
}
}
return ret;
}
int main(void)
{
int ret = -1;
int file_len = 0;
int fread_len = 0;
std::string result ;
std::string ImageA;
std::string ImageB;
char pathA[PATH_LEN] = "./1.jpg";
char pathB[PATH_LEN] = "./2.jpg";
char* PpathA = pathA;
char* PpathB = pathB;
char* PdataA = NULL;
char* PdataB = NULL;
char* Pbase64A = NULL;
char* Pbase64B = NULL;
file_len = Calculat_FlieLength(pathA);
PdataA = (char *)malloc(file_len);
Pbase64A = (char *)malloc(file_len*3/2); /*base63 = 1.33 jpg*/
fread_len = Read_Image(pathA, PdataA);
if(file_len==fread_len)
{
Base64_Code(PdataA, Pbase64A, fread_len);
ImageA = Pbase64A;
cout << "fileA len = " << file_len<<" "<< "Pbase64A len = " << strlen(Pbase64A)<< endl;
}
else
{
cout << "Image A read err" << endl;
}
file_len = Calculat_FlieLength(pathB);
PdataB = (char *)malloc(file_len);
Pbase64B = (char *)malloc(file_len*3/2);
fread_len = Read_Image(pathB, PdataB);
if(file_len==fread_len)
{
Base64_Code(PdataB, Pbase64B, fread_len);
ImageB = Pbase64B;
cout << "fileB len = " << file_len<<" "<< "Pbase64B len = " << strlen(Pbase64B) << endl;
}
else
{
cout<<"Image B read err"<<endl;
}
std::vector<std::string> InputImag;
InputImag.push_back(ImageA);
InputImag.push_back(ImageB);
ret = match(result, InputImag, AccessKey);
if(ret!=0)
{
cout<<"face_detect functtion err "<<ret<<endl;
}else
{
cout<<result<<endl;
}
if(result.empty())
{
cout<<"result id empty " <<endl;
}
std::string index_i;
ret = ReadJson_arrayObj_string(result, "result", "index_i", index_i);
if(0==ret)
{
cout << " index_i = " << index_i <<endl;
}
std::string index_j;
ret = ReadJson_arrayObj_string(result, "result", "index_j", index_j);
if(0==ret)
{
cout << " index_j = " << index_j <<endl;
}
int score = 0 ;
ret = ReadJson_arrayObj_int(result, "result", "score", score);
if(0==ret)
{
cout << " score = " << score <<endl;
}
int result_num = 0;
ret = ReadJson_Int(result, "result_num", result_num);
if(0==ret)
{
cout << " result_num = " << result_num <<endl;
}
long log_id = 0;
ret = ReadJson_Long(result, "log_id", log_id);
if(0==ret)
{
cout << " log_id = " << log_id <<endl;
}
free(PdataA);
free(Pbase64A);
free(PdataB);
free(Pbase64B);
return 0;
}
上面代码,我在百度给的接口基础上,添加了json 数据的提取接口,找了两张朝伟哥两张图片做人脸对比,识别度还是比较高的。测试图片如下:
程序运行结果如下:
aaa@qq.com:~/face_example$ ./test
fileA len = 34872 Pbase64A len = 46496
fileB len = 34413 Pbase64B len = 45884
result_code=0
{"result":[{"index_i":"0","index_j":"1","score":92.483772277832}],"result_num":1,"log_id":2462281408081911}
index_i = 0
index_j = 1
score = 92
result_num = 1
log_id = 2462281408081911
aaa@qq.com:~/face_example$
score 的值就是对比的相似度,值的范围从0到100。
工程目录:
aaa@qq.com:~/face_example$ tree -L 2
.
├── 1.jpg
├── 2.jpg
├── access_taken.cpp
├── curl
│ ├── bin
│ ├── include
│ ├── lib
│ └── share
├── face_match.cpp
├── json
│ ├── include
│ └── lib
├── json.cpp
├── Makefile
├── test
└── url.c
8 directories, 8 files
aaa@qq.com:~/face_example$
完整的工程代码可以在下面下载:
github:https://github.com/licaibiao/BaiduAI_FaceMatch.git
CSDN:http://download.csdn.net/download/li_wen01/9941088
推荐阅读