内容有点多,大概分三天写完。提前开坑省的拖延症犯了orz。//好吧拖延症果然犯了,然后第四天才继续开始更
先总结一下,全程花了三四天的白天的时间。本身其实是不复杂的,但是中间会有很多坑。专门写这个教程出来是想给同样想尝试使用这个的同学们一点帮助,希望不要遇到和我遇到的同样的问题。至于百度这个人脸识别的表现,我用了1000个人脸测试了下,其实只有100个人就是了。准确率还阔以,速度还好吧半秒左右。
这里使用VS2017+win10。不得不说,为什么遇到这么多坑,很多的原因就是版本的问题,所以刚入坑的同学们,如果时间没有那么充裕的话,不要浪费太多时间在版本问题上,如果有很多时间的话,可以是用新版本,多看看文档,也会有很多收获。
如果在配置过程中遇到了错误,可以百度。但是强烈建议先看文档,各种官方文档或者google。虽然百度可以查到很多类似的问题,但是不得不说,质量感人。
为了让新手也能看明白,下面很多内容会写的尽量傻瓜式一些。
环境主要是编译好几个依赖库,libcurl(支持https),openssl,jsoncpp。因为后期人脸库管理有base64编码的问题,我还用到了opencv,不过这个不是必须的,我只是正好有opencv所以结合opencv搞的base64编码,大概在网上找了一个代码。有时间的同学们自己写一写也行,难度不大但可能会比较费时间。
这里是个大坑,其实基本都在搞这个才浪费了这么久的时间QAQ,想想就难受。
首先去百度人脸识别那里下载sdk,如果使用api的话这一步是可以省去的。
http://ai.baidu.com/sdk
下载好以后,可以新建一个项目,把这个解压到项目目录下就好了,当然解压到其他地方也可以,不影响。
然后下载jsoncpp
https://github.com/open-source-parsers/jsoncpp
我是在这里下载的,没注意是什么版本的,反正能用就是了。。下载下来以后打开目录下的vs项目直接32位debug编译一下生成一个叫做json_vc71_libmtd.lib的库就好了。这里要说明一下,因为所有的包都是在一个项目中调用的,所以如果你这里32位debug编译,后面的也一定不要改,也不要改成活动的,如果静态就一定所有的都是静态。
可能遇到的问题:如果是vs2017之类的新版本,打开后要升级,升级后右键项目,属性,记得把windows sdk版本改一下,一般来说高级的版本支持低级的,选高的那个就好了。
编译好了以后下载openssl和curl,这里我使用的版本分别是1.0.2l和7.55.0。因为时间问题所以用了比较古老的版本,其实也没多古老就是了。
openssl下载地址:https://www.openssl.org/source/old/
curl下载地址:https://curl.haxx.se/download/
openssl解压以后里面有INSTALL.W32或是.W64的两个文件,打开好好看一下,编译不要出问题,否则很费时间。
这里大概说一下流程,不过不同的版本一定要看一下,可能会有不一样的地方。
首先要按说明中的下载ActivePerl,最新版本即可,nasm可以不下,我这里下了nasm,配置了环境变量也无限提示NASM不存在,就没有用NASM。当然,最好还是安装NASM比较好,否则也有可能会编译失败。
ActivePerl下载链接:https://www.activestate.com/activeperl/downloads
安装好一切以后,打开vs命令行,这里打开x86的那个。
然后在命令行cd到openssl目录下,输入命令perl Configure debug-VC-WIN32 no-asm --perfix=xxx
xxx这里是你编译的路径,到时候文件会生成在这里。如果不想要debug编译的话,去掉debug-这一部分就好了
输入完毕回车后,再次输入ms\do_ms
回车后输入nmake -f ms\ntdll.mak
回车后再输入nmake -f ms\ntdll.mak test 这个是测试,也可以跳过这步
回车后再输入 nmake -f ms\ntdll.mak install
静态库对应的是nt.mak,替换即可。
至此安装完毕。
这里可能会出现的问题,如果提示没有nmake的话,请将nmake的路径加入环境变量path中,nmake的路径在visual studio安装路径下的vc文件夹中,进去搜索一下,会有两个nmake.exe,一个是64位的一个是32位的,看需要就好了。
接下来就是curl了,curl是一个开源的文件传输工具。
解压完毕后,其目录下,winbulid文件夹下会有一个BUILD.WINDOWS.txt文件,具体的编译方式等都可以看这个文件,写的非常清楚。
大概说一下流程。百度的这个curl是要支持openssl的,所以要讲openssl在一起编译。需要在curl的同级目录中新建一个deps的文件夹,然后新建三个文件夹,bin,include,lib。注意是同级目录,并不是在curl目录下。
|_curl-src
|_winbuild
|
|_deps
|_ lib
|_ include
|_ bin
然后将openssl中include文件夹下的openssl文件夹(也有可能在inc32文件夹中)复制到deps中的include文件夹中。把openssl中out32dll文件夹下的文件全部复制到deps下的lib中。
复制完毕以后,和openssl一样,打开vs的x86命令行。cd到curl中winbulid目录下。因为已经提供了写好的makefile文件,所以直接输入命令 nmake /f Makefile.vc mode=static Debug=yes MACHINE=x86 RTLIBCFG=static WITH_SSL=static
如果这里需要动态链接库的话,static全部换成dll,并去掉RTLIBCFG-static这个option。
非debug将设置改为no即可。WITH_SSL是设置是否支持SSL,不需要的话去掉即可。
确定输入完毕后回车等待编译。完成后就完成了所有的编译步骤了。
接下来就是在项目中加入这些链接库和头文件了,首先,先将几个库的include中的文件全部复制到一个文件夹下,这样更方便一些,注意不要改变文件夹的名字和目录顺序。如果使用百度的sdk的话需要把sdk也放到include下,使用api的话不许要。
将需要的lib文件放在一个文件夹下,注意,动态库需要dll文件,也可以直接将dll复制到项目中。
将include目录添加到附加包含目录中(属性→C/C++→常规),将lib目录添加到链接库依赖项(属性→链接库→常规)中,将需要的lib文件名添加到附加依赖项(属性→链接库→输入)中。
libeay32.lib
json_vc71_libmtd.lib
libcurl_a_debug.lib
找不到上面三个文件的话,搜索一下就好了,一般在编译好的build目录下。
在属性→C/C++→预处理器→预处理器定义中添加BUILDING_LIBCURL HTTP_ONLY这两项。
将解决方案配置成debug/release x86或是x64(依个人需求)。这些全部完毕以后就可以测试一下啦。
这里提供一个测试代码,这里使用的api所以可以不下载百度的sdk。
下面这个代码是百度文档中提供的代码,我应该修改了一部分,因为可能出现两个报错。一个是CA证书的报错,有两种选择,一是安装最新的证书,另一个是加入这句
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
具体加哪儿,想必看一下代码就知道了吧w
提供一个文档地址:https://curl.haxx.se/docs/sslcerts.html
还有一个可能的报错是json reader的报错,大概是让你使用charreader代替reader的,最简单的办法就是转到定义把让你代替reader的那句直接注释掉。如果有时间看charreader用法的话,也可以修改代码使用CharReader。
access_token.h
#include
#include
#include
// 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存放变量
//
/**
* 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(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;
}
face.cpp
//都注释掉了,看需求删除注释吧,可以参考一下百度的官方文档,就很容易看明白了
#include "stdafx.h"
#include
#include
#include
#include
#include "access_token.h"
using namespace std;
int main()
{
//string json_search_result;
//string access_token(""); //调用api需要获取的access_token
/*************************************************************************************
//调用API,首先要获取access_token,获取一次后不许要再次获取,但每30天需要重新获取
//string access_token;
//static string access_token_result;
//get_access_token(access_token, "api_key, "secret_key");//去控制台查看key
//cout << access_token;
************************************************************************************/
/*************************************************************************************
//调用sdk 需要引用百度sdk
string app_id("");
string api_key("");
string secret_key("");
//上面三个去控制台查看即可
aip::Face client(app_id, api_key, secret_key); //创建一个客户对象,调用其中方法实现各种人脸识别,搜索等功能
Json::Value result;
string group_id("001");
string image("http://img1.gtimg.com/ent/pics/hv1/97/175/2248/146220922.jpg");//链接或是base64编码的图像
string image_type("URL");//图像类型,可选URL,BASE64
mapoptions;
options["user_id"] = "001";
result = client.search(image, image_type, group_id, options);//此处调用人脸搜索
************************************************************************************/
getchar();
return 0;
}
如果能成功获取access_token就算是基本成功啦。
百度的文档:http://ai.baidu.com/docs#/Face-Set-V3/top
然后就是人脸库的操作了,如果数据少的话,可以直接到控制台手动上传,如果数据多的话,可能是用代码比较方便一些,不过只是出于测试的话,手动更方便一些,人脸库管理的内容就不说太多了,要注意的是一点,就是要用到curl的话,如果有ca证书报错的话,按照上面说的两个方法尝试就好了,具体原因可以去libcurl的文档看。