百度人脸识别windows c++离线sdk c#接入
目录
说明
自己根据sdk封装了动态库,然后c#调用。
功能接口
设计背景
• 场景特点:
-- 网络:对于无网、局域网等情况,无法连接公网,api 方式无法运作。如政府单
位、金融保险、教育机构等,其中内网情况最为常见,私有化部署是项目开展的前提
条件。
-- 安全:即使可以连接外网,因为人脸数据的敏感性,许多客户不希望将人脸数据传
入百度服务器,如大学学生照片、部分企业员工数据等,api 形式也往往不被接受。
-- 速度:由于各地网络线路、机房部署、图片采集方式等诸多原因,api 形式往往耗
时较高,容易存在部分请求耗时过长的情况,容易影响业务正常运转。
-- 稳定:api 形式容易受网络抖动、机房故障、线上连带 bug 等影响,存在一定的不
稳定因素,可用性保障,往往成为在线调用最容易出现问题的地方。
• 客户特点:
-- 1:n-小型人脸库检索:多为通道通行、固定区域人群验证等需求,如写字楼闸机
门禁、企业考勤打卡等,人脸库范围较小,且不易经常变动。
-- 1:1-自有数据源对比:将当前采集的人脸,与其他数据源中的人脸进行对比,如
身份证芯片照、教务系统图片、档案图片等,进行快速的 1:1 对比验证。
• 核心需求:
-- 基础的人脸采集:包含人脸检测、跟踪、捕获、质量校验等基础功能,获取符合识
别条件的人脸。为之前的客户端 sdk 的标准功能,离线版本 sdk 保留以上所有能
力。
-- 本地特征抽取:所有在 sdk 中运行的人脸图片,都可以完成本地特征抽取,以便
进行对比或识别操作。
-- 1:1 对比:支持两张图片的相似度对比,可直接传入图片,也可调用本地某个人
脸特征;
-- 1:n 搜索:支持一定库大小的人脸查找,在指定的人脸集合中查找最相似的人
脸,并返回相似度分值;
sdk 包结构
效果
代码
头文件
#pragma once
#include "targetver.h"
#define win32_lean_and_mean // 从 windows 头中排除极少使用的资料
// windows 头文件:
#include <windows.h>
#include "baidu_face_api.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
//创建实例
extern "c" _declspec(dllexport) void* __cdecl create();
//实例初始化
extern "c" _declspec(dllexport) int __cdecl init(void* engine, char* model_path, char* code);
//人脸检测
extern "c" _declspec(dllexport) int __cdecl face_detect(void* engine, mat* image, char* json_result);
// 通过图片人脸特征值提取
extern "c" _declspec(dllexport) int __cdecl face_feature(void* engine, mat* image, char* json_result);
// 人脸比对(通过传图片)
extern "c" _declspec(dllexport) float __cdecl face_match_by_img(void* engine, mat* image, mat* image2);
源文件
#include "stdafx.h"
baidufaceapi *api;
//创建实例
void* __cdecl create() {
api = new baidufaceapi();
// 获取设备指纹
std::string device_id;
api->get_device_id(device_id);
std::cout << "device id is:" << device_id << std::endl;
// 获取sdk版本号
std::string version;
api->sdk_version(version);
std::cout << "sdk version:" << version << std::endl;
return api;
}
//实例初始化
int __cdecl init(void* engine, char* model_path, char* code) {
baidufaceapi* _api = (baidufaceapi*)engine;
return (int)_api->sdk_init(model_path);
}
//人脸检测
int __cdecl face_detect(void* engine, mat* image, char* json_result) {
baidufaceapi* _api = (baidufaceapi*)engine;
std::vector<facebox> box_list;
// type 0: 表示rgb 人脸检测 1:表示nir人脸检测
int type = 0;
int face_num = 0;
face_num = _api->detect(box_list, image, 0);
std::cout << "-----face_num is-------" << face_num << std::endl;
std::string res_str("");
if (face_num > 0)
{
for (int i = 0; i < face_num; i++)
{
facebox info = box_list.at(i);
// 人脸置信度
std::cout << "detect score is:" << info.score << std::endl;
// 人脸宽度
std::cout << "detect mwidth is:" << info.width << std::endl;
// 中心点x,y坐标
std::cout << "detect mcenter_x is:" << info.center_x << std::endl;
std::cout << "detect mcenter_y is:" << info.center_y << std::endl;
std::string str = ("{\"center_x\":\"") + std::to_string(info.center_x) + ("\",") +
"\"center_y\":\"" + std::to_string(info.center_y) + ("\",") +
"\"width\":\"" + std::to_string(info.width) + ("\",") +
"\"height\":\"" + std::to_string(info.height) + ("\",") +
"\"score\":\"" + std::to_string(info.score) + "\"}";
res_str = res_str + str.c_str();
res_str += ",";
}
}
if (res_str.length()>0)
{
res_str.erase(res_str.length() - 1);
}
res_str = "[" + res_str + "]";
strcpy(json_result, res_str.c_str());
return face_num;
}
// 通过图片人脸特征值提取
int __cdecl face_feature(void* engine, mat* image, char* json_result) {
baidufaceapi* _api = (baidufaceapi*)engine;
std::vector<feature> out_fea1;
std::vector<facebox> out_box1;
// 提取第一个人的特征值
// 特征值的type:传 0 可见光生活照特征值, 1、表示近红外特征值
int type = 0;
int face_num = 0;
face_num = _api->face_feature(out_fea1, out_box1, image, type);
std::cout << "face num is:" << face_num << std::endl;
int size = out_fea1.size();
std::string res_str("");
for (int i = 0; i < size; i++) {
feature feature = out_fea1.at(i);
facebox info = out_box1.at(i);
std::string str_feature = "";
for (size_t i = 0; i < feature.size; i++)
{
str_feature = str_feature + std::to_string(feature.data[i])+" ";
}
if (str_feature.length()>0)
{
str_feature.erase(str_feature.length() - 1);
}
std::string str = ("{\"center_x\":\"") + std::to_string(info.center_x) + ("\",") +
"\"center_y\":\"" + std::to_string(info.center_y) + ("\",") +
"\"width\":\"" + std::to_string(info.width) + ("\",") +
"\"height\":\"" + std::to_string(info.height) + ("\",") +
"\"score\":\"" + std::to_string(info.score) + "\","+
"\"feature\":\"" + str_feature + "\"" +
"}";
res_str = res_str + str.c_str();
res_str += ",";
}
if (res_str.length()>0)
{
res_str.erase(res_str.length() - 1);
}
res_str = "[" + res_str + "]";
strcpy(json_result, res_str.c_str());
return face_num;
}
// 人脸比对(通过传图片)
float __cdecl face_match_by_img(void* engine, mat* image, mat* image2) {
baidufaceapi* _api = (baidufaceapi*)engine;
// type 0: 表示rgb 人脸特征值 1:表示nir人脸特征值
int type = 0;
float score = _api->match(*image, *image2, type);
std::cout << "face match score is:" << score << std::endl;
return score;
}
调用代码
using faceservice.common;
using newtonsoft.json;
using opencvsharp;
using system;
using system.collections.generic;
using system.componentmodel;
using system.data;
using system.drawing;
using system.linq;
using system.security.cryptography;
using system.text;
using system.threading.tasks;
using system.windows.forms;
namespace faceservice
{
public partial class form1 : form
{
public form1()
{
initializecomponent();
}
static intptr engine;
string image_path = "";
string image_path2 = "";
private void button1_click(object sender, eventargs e)
{
engine = native.create();
string model_path = application.startuppath + "\\face";
textbox1.text = "正在初始化,请稍后……";
application.doevents();
int res = native.init(engine, model_path, "");
if (res == 0)
{
textbox1.text = "初始化成功!";
messagebox.show("初始化成功");
}
else
{
textbox1.text = "初始化失败,code:" + res;
messagebox.show("初始化失败,code:" + res);
}
}
/// <summary>
/// 人脸检测
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_click(object sender, eventargs e)
{
if (engine == intptr.zero)
{
messagebox.show("请先初始化!");
return;
}
if (image_path == "")
{
messagebox.show("请先选择图片!");
return;
}
textbox1.text = "";
if (picturebox2.image != null)
{
picturebox2.image.dispose();
}
picturebox2.image = null;
button2.enabled = false;
application.doevents();
mat img = cv2.imread(image_path);
stringbuilder json_result = new stringbuilder(1024);
int facenum = native.face_detect(engine, img.cvptr, json_result);
if (facenum > 0)
{
textbox1.text = json_result.tostring();
// 将json字符串反序列化为对象
facebox[] faceboxs = jsonconvert.deserializeobject<facebox[]>(json_result.tostring());
for (int i = 0; i < faceboxs.length; i++)
{
facebox facebox = faceboxs[i];
int x = (int)(facebox.center_x - facebox.width / 2);
int y = (int)(facebox.center_y - facebox.height / 2);
rect rect = new rect(x, y, (int)facebox.width, (int)facebox.height);
cv2.puttext(img, facebox.score.tostring("f2"), new opencvsharp.point(x, y - 10), hersheyfonts.hersheysimplex, 1, scalar.red);
cv2.rectangle(img, rect, scalar.red);
}
picturebox2.image = new bitmap(img.tomemorystream());
}
else
{
messagebox.show("未检测到人脸!");
}
button2.enabled = true;
}
string filefilter = "选择图片|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
/// <summary>
/// 选择图片
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_click(object sender, eventargs e)
{
openfiledialog ofd = new openfiledialog();
ofd.initialdirectory = application.startuppath + "\\test_img\\";
ofd.filter = filefilter;
if (ofd.showdialog() != dialogresult.ok) return;
picturebox1.image = null;
image_path = ofd.filename;
picturebox1.image = new bitmap(image_path);
textbox1.text = "";
picturebox2.image = null;
}
private void form1_load(object sender, eventargs e)
{
image_path = "test_img\\2.jpg";
picturebox1.image = new bitmap(image_path);
}
/// <summary>
/// 获取人脸特征值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_click(object sender, eventargs e)
{
if (engine == intptr.zero)
{
messagebox.show("请先初始化!");
return;
}
if (image_path == "")
{
messagebox.show("请先选择图片!");
return;
}
textbox1.text = "";
if (picturebox2.image != null)
{
picturebox2.image.dispose();
}
picturebox2.image = null;
button4.enabled = false;
application.doevents();
mat img = cv2.imread(image_path);
stringbuilder json_result = new stringbuilder(2048);
int facenum = native.face_feature(engine, img.cvptr, json_result);
if (facenum > 0)
{
textbox1.text = json_result.tostring();
}
else
{
messagebox.show("未检测到人脸!");
}
button4.enabled = true;
}
/// <summary>
/// 人脸比对
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_click(object sender, eventargs e)
{
if (engine == intptr.zero)
{
messagebox.show("请先初始化!");
return;
}
if (image_path == "")
{
messagebox.show("请先选择图片!");
return;
}
if (image_path2 == "")
{
messagebox.show("请先选择图片!");
return;
}
textbox1.text = "";
button5.enabled = false;
application.doevents();
mat img = cv2.imread(image_path);
mat img2 = cv2.imread(image_path2);
float match_score = native.face_match_by_img(engine, img.cvptr, img2.cvptr);
textbox1.text = "match score:" + match_score.tostring("f2");
button5.enabled = true;
}
private void button6_click(object sender, eventargs e)
{
openfiledialog ofd = new openfiledialog();
ofd.initialdirectory = application.startuppath + "\\test_img\\";
ofd.filter = filefilter;
if (ofd.showdialog() != dialogresult.ok) return;
image_path2 = ofd.filename;
picturebox2.image = null;
picturebox2.image = new bitmap(image_path2);
}
}
}
/*
各接口返回结果 error_code 及 msg 信息如下:
错误码 错误内容 错误描述
0 success 成功
-1 illegal_params 失败或非法参数
-2 memory_allocation_failed 内存分配失败
-3 instance_is_empty 实例对象为空
-4 model_is_empty 模型内容为空
-5 unsupport_ability_type 不支持的能力类型
-6 unsupport_infer_type 不支持的预测库类型
-7 nn_create_failed 预测库对象创建失败
-8 nn_init_failed 预测库对象初始化失败
-9 image_is_empty 图像数据为空
-10 ability_init_failed 人脸能力初始化失败
-11 ability_unload 人脸能力未加载
-12 ability_already_loaded 人脸能力已加载
-13 not_authorized 未授权
-14 ability_run_exception 人脸能力运行异常
-15 unsupport_image_type 不支持的图像类型
-16 image_transform_failed 图像转换失败
-1001 system_error 系统错误
-1002 pararm_error 参数错误
-1003 db_op_failed 数据库操作失败
-1004 no_data 没有数据
-1005 record_unexist 记录不存在
-1006 record_already_exist 记录已经存在
-1007 file_not_exist 文件不存在
-1008 get_feature_fail 提取特征值失败
-1009 file_too_big 文件太大
-1010 face_resource_not_exist 人脸资源文件不存在
-1011 feature_len_error 特征值长度错误
-1012 detect_no_face 未检测到人脸
-1013 camera_error 摄像头错误或不存在
-1014 face_instance_error 人脸引擎初始化错误
-1015 license_file_not_exist 授权文件不存在
-1016 license_key_empty 授权序列号为空
-1017 license_key_invalid 授权序列号无效
-1018 license_key_expire 授权序序列号过期
-1019 license_already_used 授权序列号已被使用
-1020 device_id_empty 设备指纹为空
-1021 network_timeout 网络超时
-1022 network_error 网络错误
-1023 conf_ini_unexist 配置 ini 文件不存在
-1024 windows_server_error 禁用在 windows server
*/
using faceservice.common;
using newtonsoft.json;
using opencvsharp;
using system;
using system.collections.generic;
using system.componentmodel;
using system.data;
using system.drawing;
using system.linq;
using system.security.cryptography;
using system.text;
using system.threading.tasks;
using system.windows.forms;
namespace faceservice
{
public partial class form1 : form
{
public form1()
{
initializecomponent();
}
static intptr engine;
string image_path = "";
string image_path2 = "";
private void button1_click(object sender, eventargs e)
{
engine = native.create();
string model_path = application.startuppath + "\\face";
textbox1.text = "正在初始化,请稍后……";
application.doevents();
int res = native.init(engine, model_path, "");
if (res == 0)
{
textbox1.text = "初始化成功!";
messagebox.show("初始化成功");
}
else
{
textbox1.text = "初始化失败,code:" + res;
messagebox.show("初始化失败,code:" + res);
}
}
/// <summary>
/// 人脸检测
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_click(object sender, eventargs e)
{
if (engine == intptr.zero)
{
messagebox.show("请先初始化!");
return;
}
if (image_path == "")
{
messagebox.show("请先选择图片!");
return;
}
textbox1.text = "";
if (picturebox2.image != null)
{
picturebox2.image.dispose();
}
picturebox2.image = null;
button2.enabled = false;
application.doevents();
mat img = cv2.imread(image_path);
stringbuilder json_result = new stringbuilder(1024);
int facenum = native.face_detect(engine, img.cvptr, json_result);
if (facenum > 0)
{
textbox1.text = json_result.tostring();
// 将json字符串反序列化为对象
facebox[] faceboxs = jsonconvert.deserializeobject<facebox[]>(json_result.tostring());
for (int i = 0; i < faceboxs.length; i++)
{
facebox facebox = faceboxs[i];
int x = (int)(facebox.center_x - facebox.width / 2);
int y = (int)(facebox.center_y - facebox.height / 2);
rect rect = new rect(x, y, (int)facebox.width, (int)facebox.height);
cv2.puttext(img, facebox.score.tostring("f2"), new opencvsharp.point(x, y - 10), hersheyfonts.hersheysimplex, 1, scalar.red);
cv2.rectangle(img, rect, scalar.red);
}
picturebox2.image = new bitmap(img.tomemorystream());
}
else
{
messagebox.show("未检测到人脸!");
}
button2.enabled = true;
}
string filefilter = "选择图片|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
/// <summary>
/// 选择图片
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_click(object sender, eventargs e)
{
openfiledialog ofd = new openfiledialog();
ofd.initialdirectory = application.startuppath + "\\test_img\\";
ofd.filter = filefilter;
if (ofd.showdialog() != dialogresult.ok) return;
picturebox1.image = null;
image_path = ofd.filename;
picturebox1.image = new bitmap(image_path);
textbox1.text = "";
picturebox2.image = null;
}
private void form1_load(object sender, eventargs e)
{
image_path = "test_img\\2.jpg";
picturebox1.image = new bitmap(image_path);
}
/// <summary>
/// 获取人脸特征值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_click(object sender, eventargs e)
{
if (engine == intptr.zero)
{
messagebox.show("请先初始化!");
return;
}
if (image_path == "")
{
messagebox.show("请先选择图片!");
return;
}
textbox1.text = "";
if (picturebox2.image != null)
{
picturebox2.image.dispose();
}
picturebox2.image = null;
button4.enabled = false;
application.doevents();
mat img = cv2.imread(image_path);
stringbuilder json_result = new stringbuilder(2048);
int facenum = native.face_feature(engine, img.cvptr, json_result);
if (facenum > 0)
{
textbox1.text = json_result.tostring();
}
else
{
messagebox.show("未检测到人脸!");
}
button4.enabled = true;
}
/// <summary>
/// 人脸比对
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_click(object sender, eventargs e)
{
if (engine == intptr.zero)
{
messagebox.show("请先初始化!");
return;
}
if (image_path == "")
{
messagebox.show("请先选择图片!");
return;
}
if (image_path2 == "")
{
messagebox.show("请先选择图片!");
return;
}
textbox1.text = "";
button5.enabled = false;
application.doevents();
mat img = cv2.imread(image_path);
mat img2 = cv2.imread(image_path2);
float match_score = native.face_match_by_img(engine, img.cvptr, img2.cvptr);
textbox1.text = "match score:" + match_score.tostring("f2");
button5.enabled = true;
}
private void button6_click(object sender, eventargs e)
{
openfiledialog ofd = new openfiledialog();
ofd.initialdirectory = application.startuppath + "\\test_img\\";
ofd.filter = filefilter;
if (ofd.showdialog() != dialogresult.ok) return;
image_path2 = ofd.filename;
picturebox2.image = null;
picturebox2.image = new bitmap(image_path2);
}
}
}
/*
各接口返回结果 error_code 及 msg 信息如下:
错误码 错误内容 错误描述
0 success 成功
-1 illegal_params 失败或非法参数
-2 memory_allocation_failed 内存分配失败
-3 instance_is_empty 实例对象为空
-4 model_is_empty 模型内容为空
-5 unsupport_ability_type 不支持的能力类型
-6 unsupport_infer_type 不支持的预测库类型
-7 nn_create_failed 预测库对象创建失败
-8 nn_init_failed 预测库对象初始化失败
-9 image_is_empty 图像数据为空
-10 ability_init_failed 人脸能力初始化失败
-11 ability_unload 人脸能力未加载
-12 ability_already_loaded 人脸能力已加载
-13 not_authorized 未授权
-14 ability_run_exception 人脸能力运行异常
-15 unsupport_image_type 不支持的图像类型
-16 image_transform_failed 图像转换失败
-1001 system_error 系统错误
-1002 pararm_error 参数错误
-1003 db_op_failed 数据库操作失败
-1004 no_data 没有数据
-1005 record_unexist 记录不存在
-1006 record_already_exist 记录已经存在
-1007 file_not_exist 文件不存在
-1008 get_feature_fail 提取特征值失败
-1009 file_too_big 文件太大
-1010 face_resource_not_exist 人脸资源文件不存在
-1011 feature_len_error 特征值长度错误
-1012 detect_no_face 未检测到人脸
-1013 camera_error 摄像头错误或不存在
-1014 face_instance_error 人脸引擎初始化错误
-1015 license_file_not_exist 授权文件不存在
-1016 license_key_empty 授权序列号为空
-1017 license_key_invalid 授权序列号无效
-1018 license_key_expire 授权序序列号过期
-1019 license_already_used 授权序列号已被使用
-1020 device_id_empty 设备指纹为空
-1021 network_timeout 网络超时
-1022 network_error 网络错误
-1023 conf_ini_unexist 配置 ini 文件不存在
-1024 windows_server_error 禁用在 windows server
*/
发表评论