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

    因为工作上的需要,最近接触到百度的AI开放平台,应用到了它上面的人脸对比功能。因为百度AI的接口开放的时间不久,使用的人不是很多,这里就百度给的API及其应用做个简单的介绍。百度的说明文档,可以在这里查看百度AI开放平台-全球领先的人工智能服务平台-百度AI开放平台

    应为我使用的是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;
}

运行结果如下:

licaibiao@ubuntu:~/face_example$ ./test 
ret=0
SecretKey:ypBbZsfyGnoT7aC5iUqPcA6kQk1wCBV0
AccessKey:24.aeb0199102972324f40e88bf7ee70228.2592000.1505703119.282335-9971270
licaibiao@ubuntu:~/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 数据的提取接口,找了两张朝伟哥两张图片做人脸对比,识别度还是比较高的。测试图片如下:


 

程序运行结果如下:

licaibiao@ubuntu:~/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
licaibiao@ubuntu:~/face_example$ 


    score 的值就是对比的相似度,值的范围从0到100。

工程目录:

licaibiao@ubuntu:~/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
licaibiao@ubuntu:~/face_example$ 

    完整的工程代码可以在下面下载:

    github:https://github.com/licaibiao/BaiduAI_FaceMatch.git

    CSDN:http://download.csdn.net/download/li_wen01/9941088

  

----------------------------------------2022.08.20:21:16----------------------------------------

由于各种原因,后续文章内容将更新到公众号,本平台将不再做更新。

CSDN上相关文章的测试工程代码,也统一放到了公众号上,可以免费免积分下载

可以通过主页上的二维码,也可以通过搜索微信公众号 liwen01 进入公众号

liwen01   2022.08.21

​​​​​​​----------------------------------------2022.08.20:21:16----------------------------------------

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

li_wen01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值