通过百度API检测人脸特征,获取颜值、年龄、性别--C语言实现

通过百度API检测人脸特征,获取颜值、年龄、性别–C语言实现

一、创建应用获取AK、SK

用到的开源库有:cJSONlibcurl

百度API获取方式:https://cloud.baidu.com/

1.注册登陆后点击:人脸识别云服务

在这里插入图片描述

2.立即使用

在这里插入图片描述

3.免费尝鲜领取后、创建应用

在这里插入图片描述

4.拿到API Key 和Secret Key

在这里插入图片描述

二、通过API获取图片的颜值、年龄、性别信息

1.获取access_token

参考:API文档

C代码如下 :用到的库有curl、cJSON
cJSONlibcurl

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);//设置URL
    curl = 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;

        //设置URL
        curl_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";		//自己的SK


char *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);//设置URL
    curl = 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)
    {
        //设置URL
        curl_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
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Yengi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值