文章目录
- 通过百度API检测人脸特征,获取颜值、年龄、性别--C语言实现
- 一、创建应用获取AK、SK
- 1.注册登陆后点击:人脸识别云服务
- 2.立即使用
- 3.免费尝鲜领取后、创建应用
- 4.拿到API Key 和Secret Key
- 二、通过API获取图片的颜值、年龄、性别信息
- 1.获取access_token
- 2.对图片进行base64编码
- 3.Post 请求,获取图片的颜值、年龄、性别
- 4.解析JSON数据
- 5.最终结果如下:
- 6.全部代码如下:
通过百度API检测人脸特征,获取颜值、年龄、性别–C语言实现
一、创建应用获取AK、SK
用到的开源库有:cJSON、libcurl
百度API获取方式:https://cloud.baidu.com/
1.注册登陆后点击:人脸识别云服务
2.立即使用
3.免费尝鲜领取后、创建应用
4.拿到API Key 和Secret Key
二、通过API获取图片的颜值、年龄、性别信息
1.获取access_token
参考:API文档
C代码如下 :用到的库有curl、cJSON
cJSON、libcurl
test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h> //stat文件属性
#include <unistd.h>
#include "cJSON.h"
#include "base64.h"
#include "curl/curl.h"
const char *pic_dir = "./xx.jpg"; //图片的路径
const char *request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect";//post请求的url 不需要修改
const char *access_token_url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials"; //获取access_token的url 不需要修改
const char *api_key = "xxxxxx"; //自己的API Key
const char *secret_key = "xxxxxxxx"; //自己的 Secret Key//声明一个结构体存数据
struct MemoryStruct {char *memory;size_t size;
};
//获取网站传回的数据
static size_t MyCallBack_WriteToken(void *contents, size_t size, size_t nmemb, void *userp)
{ size_t realSize = size * nmemb;struct MemoryStruct *mem = (struct MemoryStruct *)userp;char *ptr = realloc(mem->memory, mem->size + realSize + 1);if(!ptr) {/* out of memory! */printf("not enough memory (realloc returned NULL)\n");return 0;}mem->memory = ptr;memcpy(&(mem->memory[mem->size]), contents, realSize);mem->size += realSize;mem->memory[mem->size] = 0;return realSize;
}static int get_access_token__(struct MemoryStruct *access_token) {CURL *curl;CURLcode result_code;int error_code = 0;int bufSize = strlen(access_token_url)+strlen(api_key)+strlen(secret_key)+50;char *url = (char *)malloc(sizeof(char)*bufSize);sprintf(url,"%s&client_id=%s&client_secret=%s",access_token_url,api_key,secret_key);//设置URLcurl = curl_easy_init();if (curl) {curl_easy_setopt(curl, CURLOPT_URL, url);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);//设置传输的数据curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)access_token);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, MyCallBack_WriteToken);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;}curl_easy_cleanup(curl);error_code = 0;} else {fprintf(stderr, "curl_easy_init() failed.");error_code = 1;}return error_code;
}void get_access_tokenStr(char **str)
{struct MemoryStruct *access_token;access_token = malloc(sizeof(struct MemoryStruct));access_token->memory = malloc(1);access_token->size = 0;get_access_token__(access_token);// printf("%s\n",access_token->memory);cJSON *root = cJSON_Parse(access_token->memory);cJSON *item = cJSON_GetObjectItem(root,"access_token");*str = (char *)malloc(strlen(item->valuestring) + 1);memcpy(*str,item->valuestring,strlen(item->valuestring) + 1);// char *s = cJSON_Print(root);// printf("%s\n",s);// free(s);free(access_token->memory);free(access_token);
}/*test*/
void main(void)
{char *access_token;get_access_tokenStr(&access_token);printf("%s\n",access_token);free(access_token);return;
}
编译运行:
gcc test.c -I ./include -L ./lib -lcjson -lm
2.对图片进行base64编码
查看API文档请求格式为application/json
,图片需要进行Base64编码、图片的格式可以为PNG、JGP、JPEG、BMP
①先在目录中保存一张包含人脸的图片例如1.png
②对图片进行Base64编码
base64编码
3.Post 请求,获取图片的颜值、年龄、性别
①封装请求头
请求格式如下:
// curl发送http请求调用的回调函数,回调函数中对返回的存储在了结构体faceContet中
static size_t callback__(void *contents, size_t size, size_t nmemb, void *userp)
{size_t realSize = size * nmemb;struct MemoryStruct *mem = (struct MemoryStruct *)userp;char *ptr = realloc(mem->memory, mem->size + realSize + 1);if(!ptr) {/* out of memory! */printf("not enough memory (realloc returned NULL)\n");return 0;}mem->memory = ptr;memcpy(&(mem->memory[mem->size]), contents, realSize);mem->size += realSize;mem->memory[mem->size] = 0;return realSize; }
// 人脸检测与属性分析
static int post_request(struct MemoryStruct *faceContet,const char *request_param,const char *access_token)
{char *url;int bufSize = strlen(request_url) + strlen(access_token) + 20;url = (char *)malloc(sizeof(char)*bufSize);// https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=【调用鉴权接口获取的token】sprintf(url,"%s?access_token=%s",request_url,access_token);CURL *curl;curl = curl_easy_init();if(curl){CURLcode res;struct curl_header *header;//设置URLcurl_easy_setopt(curl,CURLOPT_URL,url);//设置协议头struct curl_slist *headers = NULL;headers = curl_slist_append(headers,"Content-Type:application/json;charset=UTF-8");curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);// "{"image":"027d8308a2ec665acb1bdf63e513bcb9","image_type":"FACE_TOKEN","face_field":"faceshape,facetype"}"curl_easy_setopt(curl, CURLOPT_POSTFIELDS,request_param);//设置post的回调函数curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)faceContet);curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,callback__);//设置传输的数据curl_easy_setopt(curl,CURLOPT_POST,1);//执行 curl_easy_perform(curl);}}
//需要传入access_token
char * get_face_detch(const char * access_token) //获取post请求返回的参数
{struct MemoryStruct *faceContet;faceContet = malloc(sizeof(struct MemoryStruct));faceContet->memory = malloc(1);faceContet->size = 0;char *request_param,*jpgBuf,*base64JpgBuf;//获取图片的base64编码作为http post请求的参数struct stat statBuf;stat(pic_dir,&statBuf); //获取文件信息int fileSize = statBuf.st_size; //获取文件大小jpgBuf = malloc(sizeof(char)*fileSize + 1);FILE *file;file = fopen(pic_dir,"r");if(file == NULL){perror("fopen");return NULL;}if(fread(jpgBuf,fileSize,1,file) == 0){printf("读取文件失败!");// getchar();exit(0);}int size = (int)((float)fileSize*1.5);base64JpgBuf = (char *)malloc(size*fileSize*sizeof(char));base64_encode_file(jpgBuf,base64JpgBuf,fileSize);request_param = (char *)malloc(strlen(base64JpgBuf) + 100);//请求参数设置sprintf(request_param,"{\"image\":\"%s\",\"image_type\":\"BASE64\",\"face_field\":\"age,gender,beauty\"}",base64JpgBuf);post_request(faceContet,request_param,access_token);free(jpgBuf);free(base64JpgBuf);free(request_param);/*test*/// cJSON *root = cJSON_Parse(faceContet->memory);// char *s = cJSON_Print(root);// printf("%s\n",s);// free(s);// printf("%s\n",faceContet->memory);return faceContet->memory;
}
4.解析JSON数据
使用cJSON解析
typedef struct PersonalInfo
{int age;char gender[GENDER_BUF_SIZE];float beauty;
}DataType;void parse_face_info(char *faceJsonStr)
{DataType data;cJSON *root,*result,*face_list,*obj,*val; root = cJSON_Parse(faceJsonStr);int flag = 0;if(root != NULL && root->type == cJSON_Object){result = cJSON_GetObjectItem(root,"result"); if(result != NULL && result->type == cJSON_Object){face_list = cJSON_GetObjectItem(result,"face_list");if(face_list != NULL && face_list->type == cJSON_Array){obj = cJSON_GetArrayItem(face_list,0);if(obj != NULL && obj->type == cJSON_Object){val = cJSON_GetObjectItem(obj,"age");data.age = val->valueint;val = cJSON_GetObjectItem(obj,"beauty");data.beauty = val->valuedouble;val = cJSON_GetObjectItem(obj,"gender");if(val != NULL && val->type == cJSON_Object){val = cJSON_GetObjectItem(val,"type");strcpy(data.gender,val->valuestring);flag = 1;}}}}}if(flag)printf("%d\t%s\t%.2f\t\n",data.age,data.gender,data.beauty);else{printf("解析失败!\n"); char *s = cJSON_Print(root);printf("%s\n",s);free(s);}cJSON_Delete(root);
}
5.最终结果如下:
颜值挺高80.23!
6.全部代码如下:
全部文件见:https://github.com/yiyihi/face_recognition
or
https://gitee.com/yyhi/face_recognition
只需要修改三个地方AK、SK、access_token即可测试
total.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "cJSON.h"
#include "curl/curl.h"
#define GENDER_BUF_SIZE 10// size_t 是一些C/C++标准在stddef.h中定义的,size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数。//声明一个结构体
struct MemoryStruct {char *memory;size_t size;
};typedef struct PersonalInfo
{int age;char gender[GENDER_BUF_SIZE];float beauty;
}DataType;const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";const char *pic_dir = "./1.png"; //图片路径const char *request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect";
const char *access_token_url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials";
const char *api_key = "xxxxx"; //自己的AK
const char *secret_key = "xxxx"; //自己的SKchar *base64_encode_file(const unsigned char * bindata, char * base64, int binlength)
{int i, j;unsigned char current;for ( i = 0, j = 0 ; i < binlength ; i += 3 ){current = (bindata[i] >> 2) ;current &= (unsigned char)0x3F;base64[j++] = base64char[(int)current];current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ;if ( i + 1 >= binlength ){base64[j++] = base64char[(int)current];base64[j++] = '=';base64[j++] = '=';break;}current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F );base64[j++] = base64char[(int)current];current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ;if ( i + 2 >= binlength ){base64[j++] = base64char[(int)current];base64[j++] = '=';break;}current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 );base64[j++] = base64char[(int)current];current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ;base64[j++] = base64char[(int)current];}base64[j] = '\0';return 0;
}//获取网站传回的数据
static size_t MyCallBack_WriteToken(void *contents, size_t size, size_t nmemb, void *userp)
{ size_t realSize = size * nmemb;struct MemoryStruct *mem = (struct MemoryStruct *)userp;char *ptr = realloc(mem->memory, mem->size + realSize + 1);if(!ptr) {/* out of memory! */printf("not enough memory (realloc returned NULL)\n");return 0;}mem->memory = ptr;memcpy(&(mem->memory[mem->size]), contents, realSize);mem->size += realSize;mem->memory[mem->size] = 0;return realSize;
}static int get_access_token__(struct MemoryStruct *access_token) {CURL *curl;CURLcode result_code;int error_code = 0;int bufSize = strlen(access_token_url)+strlen(api_key)+strlen(secret_key)+50;char *url = (char *)malloc(sizeof(char)*bufSize);sprintf(url,"%s&client_id=%s&client_secret=%s",access_token_url,api_key,secret_key);//设置URLcurl = curl_easy_init();if (curl) {curl_easy_setopt(curl, CURLOPT_URL, url);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);//设置传输的数据curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)access_token);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, MyCallBack_WriteToken);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;}curl_easy_cleanup(curl);error_code = 0;} else {fprintf(stderr, "curl_easy_init() failed.");error_code = 1;}return error_code;
}void get_access_tokenStr(char **str)
{struct MemoryStruct *access_token;access_token = malloc(sizeof(struct MemoryStruct));access_token->memory = malloc(1);access_token->size = 0;get_access_token__(access_token);// printf("%s\n",access_token->memory);cJSON *root = cJSON_Parse(access_token->memory);cJSON *item = cJSON_GetObjectItem(root,"access_token");*str = (char *)malloc(strlen(item->valuestring) + 1);memcpy(*str,item->valuestring,strlen(item->valuestring) + 1);// char *s = cJSON_Print(root);// printf("%s\n",s);// free(s);free(access_token->memory);free(access_token);
}// curl发送http请求调用的回调函数,回调函数中对返回的json格式的body进行了解析,解析结果储存在全局的静态变量当中
static size_t callback__(void *contents, size_t size, size_t nmemb, void *userp)
{size_t realSize = size * nmemb;struct MemoryStruct *mem = (struct MemoryStruct *)userp;char *ptr = realloc(mem->memory, mem->size + realSize + 1);if(!ptr) {/* out of memory! */printf("not enough memory (realloc returned NULL)\n");return 0;}mem->memory = ptr;memcpy(&(mem->memory[mem->size]), contents, realSize);mem->size += realSize;mem->memory[mem->size] = 0;return realSize; }
// 人脸检测与属性分析
static int post_request(struct MemoryStruct *faceContet,const char *request_param,const char *access_token)
{char *url;int bufSize = strlen(request_url) + strlen(access_token) + 20;url = (char *)malloc(sizeof(char)*bufSize);// https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=【调用鉴权接口获取的token】sprintf(url,"%s?access_token=%s",request_url,access_token);CURL *curl;int error_code = 0;CURLcode result_code;curl = curl_easy_init();if(curl){//设置URLcurl_easy_setopt(curl,CURLOPT_URL,url);//设置协议头struct curl_slist *headers = NULL;headers = curl_slist_append(headers,"Content-Type:application/json;charset=UTF-8");curl_easy_setopt(curl,CURLOPT_HTTPHEADER,headers);// "{"image":"027d8308a2ec665acb1bdf63e513bcb9","image_type":"FACE_TOKEN","face_field":"faceshape,facetype"}"curl_easy_setopt(curl, CURLOPT_POSTFIELDS,request_param);//设置post的回调函数curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)faceContet);curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,callback__);//设置传输的数据curl_easy_setopt(curl,CURLOPT_POST,1);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;}curl_easy_cleanup(curl);error_code = 0;} else {fprintf(stderr, "curl_easy_init() failed.");error_code = 1;}
}char * get_face_detch(const char * access_token) //获取post请求返回的参数
{struct MemoryStruct *faceContet;faceContet = malloc(sizeof(struct MemoryStruct));faceContet->memory = malloc(1);faceContet->size = 0;char *request_param,*jpgBuf,*base64JpgBuf;//获取图片的base64编码作为http post请求的参数struct stat statBuf;stat(pic_dir,&statBuf); //获取文件信息int fileSize = statBuf.st_size; //获取文件大小jpgBuf = malloc(sizeof(char)*fileSize + 1);FILE *file;file = fopen(pic_dir,"r");if(file == NULL){perror("fopen");return NULL;}if(fread(jpgBuf,fileSize,1,file) == 0){printf("读取文件失败!");// getchar();exit(0);}int size = (int)((float)fileSize*1.5);base64JpgBuf = (char *)malloc(size*sizeof(char));if(base64JpgBuf == NULL){perror("malloc error!");return NULL;}bzero(base64JpgBuf,size);base64_encode_file(jpgBuf,base64JpgBuf,fileSize);request_param = (char *)malloc(size + 100);sprintf(request_param,"{\"image\":\"%s\",\"image_type\":\"BASE64\",\"face_field\":\"age,gender,beauty\"}",base64JpgBuf);post_request(faceContet,request_param,access_token);free(jpgBuf);free(base64JpgBuf);free(request_param);fclose(file);/*test*/// cJSON *root = cJSON_Parse(faceContet->memory);// char *s = cJSON_Print(root);// printf("%s\n",s);// free(s);// printf("%s\n",faceContet->memory);return faceContet->memory;
}void parse_face_info(char *faceJsonStr)
{DataType data;cJSON *root,*result,*face_list,*obj,*val; root = cJSON_Parse(faceJsonStr);int flag = 0;if(root != NULL && root->type == cJSON_Object){result = cJSON_GetObjectItem(root,"result"); if(result != NULL && result->type == cJSON_Object){face_list = cJSON_GetObjectItem(result,"face_list");if(face_list != NULL && face_list->type == cJSON_Array){obj = cJSON_GetArrayItem(face_list,0);if(obj != NULL && obj->type == cJSON_Object){val = cJSON_GetObjectItem(obj,"age");data.age = val->valueint;val = cJSON_GetObjectItem(obj,"beauty");data.beauty = val->valuedouble;val = cJSON_GetObjectItem(obj,"gender");if(val != NULL && val->type == cJSON_Object){val = cJSON_GetObjectItem(val,"type");strcpy(data.gender,val->valuestring);flag = 1;}}}}}if(flag)printf("%d\t%s\t%.2f\t\n",data.age,data.gender,data.beauty);else{printf("解析失败!\n"); char *s = cJSON_Print(root);printf("%s\n",s);free(s);}cJSON_Delete(root);
}int main(int argc, char const *argv[])
{char *access_token,*faceJsonStr;curl_global_init(CURL_GLOBAL_ALL);// get_access_tokenStr(&access_token); //只需要一个月获取一次access_token = "xxxxxxxx"; //自己的access_token// printf("%s\n",access_token);faceJsonStr = get_face_detch(access_token);parse_face_info(faceJsonStr);free(faceJsonStr);return 0;
}// libcurl参考:
// https://curl.se/libcurl/c/example.html
编译运行
gcc total.c -I ./include -L ./lib -lcurl -lcjson -lm
./a.out