目录
六、百度智能云人脸库的创建
七、人脸识别SDK的导入
八、百度云平台的接入
六、百度智能云人脸库的创建
在百度智能云的人脸识别控制台中,申请领取免费资源,在进一步页面中我们选择领取全部免费接口即可
接下来在左侧公有云服务的应用列表中,创建应用,注意,需要将应用归属选择为个人。3
创建完成后即可看到创建情况:
接下来在可视化人脸库中新建组,上传待识别的照片即可。
七、人脸识别SDK的导入
我们可以使用百度提供的SDK完成人脸信息的上传和比对信息的接收。SDK的下载地址为SDK下载_文字识别SDK_语音识别SDK-百度AI开放平台 (baidu.com), 我们选择人脸识别中的C HTTP SDK进行下载,点击使用说明即可进入该SDK的说明文档。
根据SDK的官方文档说明,有五个步骤来使用该SDK:
- 下载压缩包
- 接下来将下载好的压缩文件解压,并放到我们虚拟机中的对应代码文件处。接下来我们将之前写的main.cpp放到解压好的aip-cpp-sdk-4.16.4文件夹中
- 安装依赖库libcurl openssl和jsoncpp,我们使用以下命令依次安装
sudo pkg-get install libcurl4-openssl-dev
sudo pkg-get install openssl
sudo pkg-get install libjsoncpp-dev
g++ main.cpp -o main -lopencv_highgui -lopencv_core -lopencv_imgproc -lopencv_objdetect -lcurl -lcrypto -ljsoncpp -std=c++11
- 在main.cpp中加入include "face.h"和using namespace aip
include "face.h"
using namespace aip
如果编译报错base/http.h:23:23: fatal error: json/json.h: 没有这个文件或文件夹,那我们将base文件夹中的http.h文件第23行的#include <json/json.h>改为#include <jsoncpp/json/json.h>
同理,编译报错base/base.h:21:23: fatal error: json/json.h: 没有这个文件或文件夹时,我们将base.h21行中的#include <json/json.h>改为#include <jsoncpp/json/json.h>
编译报错base.utils.h:21:25:fatal error:openssl/evp.h:没有这个文件或文件夹时,需要安装一个新的库文件
sudo apt-get install lib-ssl-dev
八、百度云平台的接入
在之前说的SDK官方文档中,我们按照说明进行。
使用刚刚你创建应用时提供的ID,Key和Serect
接下来使用SDK文档中人脸搜索的client.search方法
该函数的参数为:
因此,我们需要先定义一个std::string类型的image和image_type,之前的图片格式是jpg的,所以需要进行一下转换,变成base64格式的
std::string base64Img;
json::value result;
base64Img = base64_encode((char *)jpgBuf.data(), jpgBuf().size()); //格式转换为base64
result = client.search(base64Img, "BASE64", "Student", aip::null); //这里的"Student"是你之前新建的人脸分组的名称
上述代码段的前两行需要放在for循环前面,后两行放在for循环内部的imencode函数后即可
接下来编译,会报错找不到函数search,这是因为我们下载的SDK中没有search方法,我们使用下面的代码替换“face.h”中的代码即可。现在即可正常编译运行。
/**
* Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @author baidu aip
*/
#ifndef __AIP_FACE_H__
#define __AIP_FACE_H__
#include "base/base.h"
namespace aip {
class Face: public AipBase
{
public:
std::string _faceverify =
"https://aip.baidubce.com/rest/2.0/face/v4/faceverify";
std::string _detect =
"https://aip.baidubce.com/rest/2.0/face/v2/detect";
std::string _match =
"https://aip.baidubce.com/rest/2.0/face/v2/match";
std::string _identify =
"https://aip.baidubce.com/rest/2.0/face/v2/identify";
std::string _verify =
"https://aip.baidubce.com/rest/2.0/face/v2/verify";
std::string _user_add =
"https://aip.baidubce.com/rest/2.0/face/v2/faceset/user/add";
std::string _user_update =
"https://aip.baidubce.com/rest/2.0/face/v2/faceset/user/update";
std::string _user_delete =
"https://aip.baidubce.com/rest/2.0/face/v2/faceset/user/delete";
std::string _user_get =
"https://aip.baidubce.com/rest/2.0/face/v2/faceset/user/get";
std::string _group_getlist =
"https://aip.baidubce.com/rest/2.0/face/v2/faceset/group/getlist";
std::string _group_getusers =
"https://aip.baidubce.com/rest/2.0/face/v2/faceset/group/getusers";
std::string _group_adduser =
"https://aip.baidubce.com/rest/2.0/face/v2/faceset/group/adduser";
std::string _group_deleteuser =
"https://aip.baidubce.com/rest/2.0/face/v2/faceset/group/deleteuser";
std::string _face_verify_v4 =
"https://aip.baidubce.com/rest/2.0/face/v4/mingjing/verify";
std::string _face_match_v4 =
"https://aip.baidubce.com/rest/2.0/face/v4/mingjing/match";
std::string _online_picture_live_v4 = "https://aip.baidubce.com/rest/2.0/face/v4/faceverify";
std::string _face_search = "https://aip.baidubce.com/rest/2.0/face/v3/search";
//"https://aip.baidubce.com/rest/2.0/face/capture/search";//
Face(const std::string & app_id, const std::string & ak, const std::string & sk): AipBase(app_id, ak, sk)
{
}
std::string vector_join_base64(const std::vector<std::string> & v_images) {
std::string images;
size_t count = v_images.size();
for (size_t i = 0; i < count;i++)
{
std::string image = v_images[i];
images += base64_encode(image.c_str(), (int) image.size());
if (i != count) {
images += ",";
}
}
return images;
}
/**
* detect
* @param image 图像文件二进制内容,可以使用aip::get_file_content函数获取
* options 可选参数:
* max_face_num 最多处理人脸数目,默认值1
* face_fields 包括age,beauty,expression,faceshape,gender,glasses,landmark,race,qualities信息,逗号分隔,默认只返回人脸框、概率和旋转角度
*/
Json::Value detect(
std::string const & image,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["image"] = base64_encode(image.c_str(), (int) image.size());
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_detect, null, data, null);
return result;
}
/**
* match
* @param images vector多图图像文件二进制内容,vector中每一项可以使用aip::get_file_content函数获取
* options 可选参数:
* ext_fields 返回质量信息,取值固定:目前支持qualities(质量检测)。(对所有图片都会做改处理)
* image_liveness 返回的活体信息,“faceliveness,faceliveness” 表示对比对的两张图片都做活体检测;“,faceliveness” 表示对第一张图片不做活体检测、第二张图做活体检测;“faceliveness,” 表示对第一张图片做活体检测、第二张图不做活体检测;<br>**注:需要用于判断活体的图片,图片中的人脸像素面积需要不小于100px\*100px,人脸长宽与图片长宽比例,不小于1/3**
* types 请求对比的两张图片的类型,示例:“7,13”<br>**12**表示带水印证件照:一般为带水印的小图,如公安网小图<br>**7**表示生活照:通常为手机、相机拍摄的人像图片、或从网络获取的人像图片等<br>**13**表示证件照片:如拍摄的身份证、工卡、护照、学生证等证件图片,**注**:需要确保人脸部分不可太小,通常为100px\*100px
*/
Json::Value match(
const std::vector<std::string> & images,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["images"] = vector_join_base64(images);
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_match, null, data, null);
return result;
}
/**
* identify
* @param group_id 用户组id(由数字、字母、下划线组成),长度限制128B,多个用户组id,用逗号分隔
* @param image 图像文件二进制内容,可以使用aip::get_file_content函数获取
* options 可选参数:
* ext_fields 特殊返回信息,多个用逗号分隔,取值固定: 目前支持faceliveness(活体检测)。**注:需要用于判断活体的图片,图片中的人脸像素面积需要不小于100px\*100px,人脸长宽与图片长宽比例,不小于1/3**
* user_top_num 返回用户top数,默认为1,最多返回5个
*/
Json::Value identify(
std::string const & group_id,
std::string const & image,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["group_id"] = group_id;
data["image"] = base64_encode(image.c_str(), (int) image.size());
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_identify, null, data, null);
return result;
}
/**
* verify
* @param uid 用户id(由数字、字母、下划线组成),长度限制128B
* @param image 图像文件二进制内容,可以使用aip::get_file_content函数获取
* @param group_id 用户组id(由数字、字母、下划线组成),长度限制128B,多个用户组id,用逗号分隔
* options 可选参数:
* top_num 返回用户top数,默认为1
* ext_fields 特殊返回信息,多个用逗号分隔,取值固定: 目前支持faceliveness(活体检测)。**注:需要用于判断活体的图片,图片中的人脸像素面积需要不小于100px\*100px,人脸长宽与图片长宽比例,不小于1/3**
*/
Json::Value verify(
std::string const & uid,
std::string const & image,
std::string const & group_id,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["uid"] = uid;
data["image"] = base64_encode(image.c_str(), (int) image.size());
data["group_id"] = group_id;
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_verify, null, data, null);
return result;
}
/**
* user_add
* @param uid 用户id(由数字、字母、下划线组成),长度限制128B
* @param user_info 用户资料,长度限制256B
* @param group_id 用户组id,标识一组用户(由数字、字母、下划线组成),长度限制128B。如果需要将一个uid注册到多个group下,group\_id需要用多个逗号分隔,每个group_id长度限制为48个英文字符。**注:group无需单独创建,注册用户时则会自动创建group。**<br>**产品建议**:根据您的业务需求,可以将需要注册的用户,按照业务划分,分配到不同的group下,例如按照会员手机尾号作为groupid,用于刷脸支付、会员计费消费等,这样可以尽可能控制每个group下的用户数与人脸数,提升检索的准确率
* @param image 图像文件二进制内容,可以使用aip::get_file_content函数获取
* options 可选参数:
* action_type 参数包含append、replace。**如果为“replace”,则每次注册时进行替换replace(新增或更新)操作,默认为append操作**。例如:uid在库中已经存在时,对此uid重复注册时,新注册的图片默认会**追加**到该uid下,如果手动选择`action_type:replace`,则会用新图替换库中该uid下所有图片。
*/
Json::Value user_add(
std::string const & uid,
std::string const & user_info,
std::string const & group_id,
std::string const & image,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["uid"] = uid;
data["user_info"] = user_info;
data["group_id"] = group_id;
data["image"] = base64_encode(image.c_str(), (int) image.size());
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_user_add, null, data, null);
return result;
}
/**
* user_update
* @param uid 用户id(由数字、字母、下划线组成),长度限制128B
* @param image 图像文件二进制内容,可以使用aip::get_file_content函数获取
* @param user_info 用户资料,长度限制256B
* @param group_id 更新指定groupid下uid对应的信息
* options 可选参数:
* action_type 目前仅支持replace,uid不存在时,不报错,会自动变为注册操作;未选择该参数时,如果uid不存在会提示错误
*/
Json::Value user_update(
std::string const & uid,
std::string const & image,
std::string const & user_info,
std::string const & group_id,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["uid"] = uid;
data["image"] = base64_encode(image.c_str(), (int) image.size());
data["user_info"] = user_info;
data["group_id"] = group_id;
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_user_update, null, data, null);
return result;
}
/**
* user_delete
* @param uid 用户id(由数字、字母、下划线组成),长度限制128B
* @param group_id 删除指定groupid下uid对应的信息
* options 可选参数:
*/
Json::Value user_delete(
std::string const & uid,
std::string const & group_id,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["uid"] = uid;
data["group_id"] = group_id;
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_user_delete, null, data, null);
return result;
}
/**
* user_get
* @param uid 用户id(由数字、字母、下划线组成),长度限制128B
* options 可选参数:
* group_id 选择指定group_id则只查找group列表下的uid内容,如果不指定则查找所有group下对应uid的信息
*/
Json::Value user_get(
std::string const & uid,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["uid"] = uid;
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_user_get, null, data, null);
return result;
}
/**
* group_getlist
* options 可选参数:
* start 默认值0,起始序号
* end 返回数量,默认值100,最大值1000
*/
Json::Value group_getlist(
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_group_getlist, null, data, null);
return result;
}
/**
* group_getusers
* @param group_id 用户组id(由数字、字母、下划线组成),长度限制128B
* options 可选参数:
* start 默认值0,起始序号
* end 返回数量,默认值100,最大值1000
*/
Json::Value group_getusers(
std::string const & group_id,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["group_id"] = group_id;
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_group_getusers, null, data, null);
return result;
}
/**
* group_adduser
* @param group_id 用户组id(由数字、字母、下划线组成),长度限制128B,多个用户组id,用逗号分隔
* @param uid 用户id(由数字、字母、下划线组成),长度限制128B
* @param src_group_id 从指定group里复制信息
* options 可选参数:
*/
Json::Value group_adduser(
std::string const & group_id,
std::string const & uid,
std::string const & src_group_id,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["group_id"] = group_id;
data["uid"] = uid;
data["src_group_id"] = src_group_id;
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_group_adduser, null, data, null);
return result;
}
/**
* group_deleteuser
* @param group_id 用户组id(由数字、字母、下划线组成),长度限制128B,多个用户组id,用逗号分隔
* @param uid 用户id(由数字、字母、下划线组成),长度限制128B
* options 可选参数:
*/
Json::Value group_deleteuser(
std::string const & group_id,
std::string const & uid,
const std::map<std::string, std::string> & options)
{
std::map<std::string, std::string> data;
data["group_id"] = group_id;
data["uid"] = uid;
std::copy(options.begin(), options.end(), std::inserter(data, data.end()));
Json::Value result =
this->request(_group_deleteuser, null, data, null);
return result;
}
/**
* 人脸 - 人脸实名认证V4
* 基于姓名和身份证号,调取公安权威数据源人脸图,将当前获取的人脸图片,与此公安数据源人脸图进行对比,得出比对分数,并基于此进行业务判断是否为同一人
* @param idCardNumber 身份证件号
* @param name 姓名(需要是 utf8 编码)
* @param image 图片信息(数据大小应小于10M 分辨率应小于1920*1080),5.2版本SDK请求时已包含在加密数据data中,无需额外传入
* options 可选参数:
* quality_control 质量控制参数
*/
Json::Value faceMingJingVerify(
const std::string& idCardNumber,
const std::string& name,
std::string* image,
std::map<std::string, std::string> options)
{
std::string access_token = this->getAccessToken();
Json::Value data;
data["id_card_number"] = idCardNumber;
data["name"] = name;
if (image != nullptr) {
data["image"] = *image;
}
std::map< std::string,std::string >::iterator it ;
for(it = options.begin(); it != options.end(); it++)
{
data[it->first] = it->second;
}
std::string mid = "?access_token=";
std::string url = _face_verify_v4 + mid + access_token;
Json::Value result =
this->request_com(url, data);
return result;
}
/**
* 人脸 - 人脸对比V4
* 用于比对多张图片中的人脸相似度并返回两两比对的得分,可用于判断两张脸是否是同一人的可能性大小
* @param image 图片信息(数据大小应小于10M 分辨率应小于1920*1080),5.2版本SDK请求时已包含在加密数据data中,无需额外传入
* @param imageType 图片类型
* @param registerImage 图片信息(总数据大小应小于10M),图片上传方式根据image_type来判断。本图片特指客户服务器上传图片,非加密图片Base64值
* @param registerImageType 图片类型
* options 可选参数
*/
Json::Value faceMingJingMatch(
std::string * image,
std::string * imageType,
const std::string& registerImage,
const std::string& registerImageType,
std::map<std::string, std::string> options)
{
std::string access_token = this->getAccessToken();
Json::Value data;
if (image != nullptr) {
data["image"] = *image;
}
if (imageType != nullptr) {
data["image_type"] = *imageType;
}
data["register_image"] = registerImage;
data["register_image_type"] = registerImageType;
std::map< std::string,std::string >::iterator it ;
for(it = options.begin(); it != options.end(); it++)
{
data[it->first] = it->second;
}
std::string mid = "?access_token=";
std::string url = _face_match_v4 + mid + access_token;
Json::Value result =
this->request_com(url, data);
return result;
}
/**
* 人脸 - 在线图片活体V4
* 基于单张图片,判断图片中的人脸是否为二次翻拍
* @param sdkVersion sdk版本
* options 可选参数
*/
Json::Value onlinePictureLiveV4(
const std::string& sdkVersion,
std::vector<std::string>& imageList,
std::map<std::string, std::string> options)
{
std::string access_token = this->getAccessToken();
Json::Value data;
data["sdk_version"] = sdkVersion;
Json::Value imageListJson;
for (std::string image : imageList) {
imageListJson.append(image);
}
data["image_list"] = imageListJson;
std::map< std::string,std::string >::iterator it ;
for(it = options.begin(); it != options.end(); it++)
{
data[it->first] = it->second;
}
std::string mid = "?access_token=";
std::string url = _online_picture_live_v4 + mid + access_token;
Json::Value result =
this->request_com(url, data);
return result;
}
Json::Value search(
std::string const & image,
std::string const & imageType,
std::string const & group_id,
const std::map<std::string, std::string> & options)
{
std::string access_token = this->getAccessToken();
Json::Value data;
data["image"] = image;
data["image_type"] = imageType;
data["group_id_list"] = group_id;
std::string mid = "?access_token=";
std::string url = _face_search + mid + access_token;
Json::Value result =
this->request_com(url, data);
return result;
}
};
}
#endif
到该部分截止,完整代码为:
#include <iostream>
#include "opencv2/opencv.hpp"
#include "face.h"
using namespace std;
using namespace cv;
using namespace aip;
int main()
{
VideoCapture cap(0); // open the default camera
if(!cap.isOpened()) // check if we succeeded
{
cout<<"Camera open failed!"<<endl;
return -1;
}
cout<<"Camera open successfully!"<<endl;
// 设置APPID/AK/SK
std::string app_id = "你的app id";
std::string api_key = "你的api key";
std::string secret_key = "你的secret key";
aip::Face client(app_id, api_key, secret_key);
Mat img;
Mat grayImg;
Mat equalizeImg;
vector<Rect> faces;
Mat faceImg;
vector<uchar> jpgBuf;
std::string base64Img;
Json::Value result;
CascadeClassifier classifier("/usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml");
for(;;)
{
cap >> img; // get a new img from camera
cvtColor(img, grayImg, CV_BGR2GRAY); //灰度处理
equalizeHist(grayImg,equalizeImg); //均衡化处理
classifier.detectMultiScale(equalizeImg, faces); //检测人脸并返回在facas中
if(faces.size())
{
rectangle(equalizeImg, faces[0], Scalar(255,255,255)); //绘制矩形框
faceImg = equalizeImg(faces[0]);
imencode(".jpg", faceImg, jpgBuf); //将图片编码为jpg格式后存到jpgBuf中
base64Img = base64_encode((char *)jpgBuf.data(), jpgBuf.size()); //格式转换为base64
result = client.search(base64Img, "BASE64", "Student", aip::null); //这里的"Student"是你之前新建的人脸分组的名称
}
else
cout<<"No face detected!"<<endl;
imshow("video", equalizeImg); //在video窗口中展示图片
waitKey(40); //设置帧率(40ms读取一帧)
}
return 0;
}