欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

百度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 数据的提取接口,找了两张朝伟哥两张图片做人脸对比,识别度还是比较高的。测试图片如下:

百度AI——人脸识别的简单应用

百度AI——人脸识别的简单应用


程序运行结果如下:

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


上一篇:

下一篇: