在windows和linux下使用cmake、dlib编译人脸识别动态链接库
windows和linux下,使用cmake将dlib开源库进行封装方便调用的人脸识别动态链接库,方便其他语言调用。
·
在windows和linux下使用cmake、dlib编译人脸识别动态链接库
开发人脸识别应用时,由于前端设备及操作系统种类繁多,如果选择在侵短实现识别功能适配工作较为繁琐,故计划将人脸识别功能在后端实现从而统一为应用提供服务。需要对dlib进行封装以供其他语言调用。
前提:cmake安装及dlib的编译
使用cmake将dlib编译成静态库lib文件,或者动态链接库(windows上为dll,linux上为so)。
开发环境
windows
win11
cmake-3.32.2
Microsoft Visual Studio 2015
linux
redhat7.6
cmake-3.25.2
gcc-9.3.1
CMakeLists.txt 及 c++代码
CMakeLists.txt
CMAKE_MINIMUN_REQUIRED(VERSION 2.8.4)
PROJECT(facerecog)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O2 -DDLIB_JPEG_SUPPORT")
IF(UNIX)
INCLUDE_DIRECTORIES(/root/dlib-19.24)
ELSE()
ADD_DEFINITIONS(-DFRDLL_EXPORTS)
INCLUDE_DIRECTORIES(D:/FaceRecognize/dlib-19.24)
ENDIF()
IF(UNIX)
LINK_DIRECTORIES(/root/dlib-19.24/build/dlib)
ELSE()
LINK_DIRECTORIES(D:/FaceRecognize/dlib-19.24/build/dlib/Release)
ENDIF()
#ADD_EXECUTABLE(facerecog dlib_test.cpp)
ADD_LIBRARY(facerecog SHARED facerecoglib.h facerecoglib.cpp)
IF(UNIX)
#TARGET_LINK_LIBRARIES(facerecog dlib)
TARGET_LINK_LIBRARIES(facerecog libdlib.so)
TARGET_LINK_LIBRARIES(facerecog pthread)
ELSE()
TARGET_LINK_LIBRARIES(facerecog dlib19.24.0_release_64bit_msvc1900.lib)
ENDIF()
facerecoglib.h
#ifndef FACERECOGLIB_H
#define FACERECOGLIB_H
#ifdef _WINDOWS
#ifdef FRDLL_EXPORTS
#define FRDLL_API __declspec(dllexport)
#else
#define FRDLL_API __declspec(dllimport)
#endif
#else
#define FRDLL_API
#endif
extern "C"
{
// 功能:初始化特征库,读取并保存基准图像文件夹中所有人脸特征值及特征信息(文件
FRDLL_API int fg_init(const char* featurepicdir,float threshold);
// 功能:识别路径未picpath的图片,返回对应的人员信息
FRDLL_API char* fg_recog(const char* picpath);
// 功能:识别是否匹配特定人脸特征
FRDLL_API int fg_recogspecial(const char* picpath,const char* featureinfo);
// 功能:插入新特征值到特征库
FRDLL_API int fb_insertfeature(const char* picpath);
// 功能:删除指定的特征值及特征信息
FRDLL_API int fb_deletefeature(const char* featureinfo);
}
#endif
facerecoglib.cpp
//尽量减少对其他库的依赖,未使用图形及opencv支持
#include <algorithm>
#include <dlib/dnn.h>
#include <dlib/clustering.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_io.h>
#include <iostream>
#include <vector>
#include <string>
#include <map>
#ifdef _WINDOWS
#include "io.h"
#else
#include <dirent.h>
#endif // _WINDOWS
#include "facerecoglib.h"
using namespace dlib;
using namespace std;
template <template <int, template<typename>class, int, typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual = add_prev1<block<N, BN, 1, tag1<SUBNET>>>;
template <template <int, template<typename>class, int, typename> class block, int N, template<typename>class BN, typename SUBNET>
using residual_down = add_prev2<avg_pool<2, 2, 2, 2, skip1<tag2<block<N, BN, 2, tag1<SUBNET>>>>>>;
template <int N, template <typename> class BN, int stride, typename SUBNET>
using block = BN<con<N, 3, 3, 1, 1, relu<BN<con<N, 3, 3, stride, stride, SUBNET>>>>>;
template <int N, typename SUBNET> using ares = relu<residual<block, N, affine, SUBNET>>;
template <int N, typename SUBNET> using ares_down = relu<residual_down<block, N, affine, SUBNET>>;
template <typename SUBNET> using alevel0 = ares_down<256, SUBNET>;
template <typename SUBNET> using alevel1 = ares<256, ares<256, ares_down<256, SUBNET>>>;
template <typename SUBNET> using alevel2 = ares<128, ares<128, ares_down<128, SUBNET>>>;
template <typename SUBNET> using alevel3 = ares<64, ares<64, ares<64, ares_down<64, SUBNET>>>>;
template <typename SUBNET> using alevel4 = ares<32, ares<32, ares<32, SUBNET>>>;
using anet_type = loss_metric<fc_no_bias<128, avg_pool_everything<
alevel0<
alevel1<
alevel2<
alevel3<
alevel4<
max_pool<3, 3, 2, 2, relu<affine<con<32, 7, 7, 2, 2,
input_rgb_image_sized<150>
>>>>>>>>>>>>;
frontal_face_detector detector;
shape_predictor predictor;
anet_type net;
float frthreshold = 0.4;
std::map<std::string,matrix<float, 0, 1>> mapFeature;
static char retstr[255];
//返回图像img中所有人脸特征值
std::vector<matrix<float, 0, 1>> GetFaceFeature(matrix<rgb_pixel> img)
{
std::vector<matrix<float, 0, 1>> features;
std::vector<dlib::rectangle> dets = detector(img);
std::vector<matrix<rgb_pixel>> faces;
for (auto const& det : dets)
{
auto shape = predictor(img, det);
matrix<rgb_pixel> face_chip;
extract_image_chip(img, get_face_chip_details(shape, 150, 0.25), face_chip);
faces.push_back(move(face_chip));
}
std::vector<matrix<float, 0, 1>> face_descriptors = net(faces);
for (auto const& feature : face_descriptors)
{
features.push_back(feature);
}
return features;
}
#读取strfeaturepicdir路径下所有图片作为识别基准数据
int CreateDataset(std::string strfeaturepicdir)
{
mapFeature.clear();
std::vector<std::string> arrFileNames; //图片完整路径
std::vector<std::string> arrLabels; //图片名称,无扩展名,作为识别输出信息
#ifdef _WINDOWS
_finddata_t file;
intptr_t HANDLE;
std::string strdir = strfeaturepicdir + "\\*.*";
HANDLE = _findfirst(strdir.c_str(), &file);
if (HANDLE == -1L)
{
return -1;
}
do {
//判断是否有子目录
if (file.attrib & _A_SUBDIR == 0)
{
std::string fileName = file.name;
if (fileName.find(".jpg") != string::npos || fileName.find(".jpeg") != string::npos
|| fileName.find(".bmp") != string::npos || fileName.find(".JPEG") != string::npos
|| fileName.find(".JPG") != string::npos || fileName.find(".BMP") != string::npos)
{
std::string label = fileName.find_last_of('.') == string::npos ? fileName : fileName.substr(0, fileName.find_last_of('.'));
fileName = strfeaturepicdir + "\\" + fileName;
arrFileNames.push_back(fileName);
arrLabels.push_back(label);
}
}
} while (_findnext(HANDLE, &file) == 0);
_findclose(HANDLE);
#else
DIR *dir;
struct dirent *ptr;
if ((dir = opendir(strfeaturepicdir.c_str())) == NULL)
{
return -1;
}
while ((ptr = readdir(dir)) != NULL)
{
if (ptr->d_name[0] == '.')
continue;
if (ptr->d_type == 8)
{
std::string fileName = ptr->d_name;
if (fileName.find(".jpg") != string::npos || fileName.find(".jpeg") != string::npos
|| fileName.find(".bmp") != string::npos || fileName.find(".JPEG") != string::npos
|| fileName.find(".JPG") != string::npos || fileName.find(".BMP") != string::npos)
{
std::string label = fileName.find_last_of('.') == string::npos ? fileName : fileName.substr(0,fileName.find_last_of('.'));
fileName = strfeaturepicdir + "//" + fileName;
arrFileNames.push_back(fileName);
arrLabels.push_back(label);
}
}
}
closedir(dir);
#endif // _WINDOWS
for (int k = 0; k < arrFileNames.size(); k++)
{
matrix<rgb_pixel> img;
try
{
load_image(img, arrFileNames[k]);
}
catch(exception& e)
{
cout << "\nexception thrown!" << endl;
cout << e.what() << endl;
return -5;
}
std::vector<matrix<float, 0, 1>> features = GetFaceFeature(img);
if (features.size() == 0 || features.size() > 1)
return -2;
else
mapFeature.insert(pair<string,matrix<float, 0, 1>>(arrLabels[k],features[0]));
}
return mapFeature.size();
}
std::string GetRecogInfo(matrix<float, 0, 1> predict_value)
{
std::string strInfo;
float min_dis = 10000;
for(std::map<std::string,matrix<float, 0, 1>>::iterator it = mapFeature.begin(); it != mapFeature.end(); it++)
{
float dis = (float)length(predict_value - it->second);
if (min_dis > dis)
{
min_dis = dis;
strInfo = it->first;
}
}
if (min_dis > frthreshold)
strInfo = "UNKNOWN";
return strInfo;
}
int fg_init(const char* picdir,float threshold)
{
frthreshold = threshold;
try
{
detector = get_frontal_face_detector();
deserialize("model//shape_predictor_68_face_landmarks.dat") >> predictor;
deserialize("model//dlib_face_recognition_resnet_model_v1.dat") >> net;
}
catch (exception& e)
{
cout << "\nexception thrown!" << endl;
cout << e.what() << endl;
return -3;
}
std::string strpicdir = picdir;
return CreateDataset(strpicdir);
}
char* fg_recog(const char* picpath)
{
if(mapFeature.size() == 0)
return "NOFACEFEATURES";
matrix<rgb_pixel> img;
try{
load_image(img, picpath);
}
catch(exception& e)
{
cout << "\nexception thrown!" << endl;
cout << e.what() << endl;
return "CANNOTOPENIMG";
}
std::vector<matrix<float, 0, 1>> fsrc = GetFaceFeature(img);
if(fsrc.size() == 0)
return "NOSOURCEFACE";
if(fsrc.size() > 1)
return "MOREFACES";
std::string strRet = GetRecogInfo(fsrc[0]);
if (strRet.length() > 254)
return "";
strcpy(retstr, strRet.c_str());
return retstr;
}
int fg_recogspecial(const char* picpath,const char* featureinfo)
{
string strfeatureinfo = featureinfo;
if(strfeatureinfo.empty())
return -1;
matrix<rgb_pixel> img;
try
{
load_image(img, picpath);
}
catch(exception& e)
{
cout << "\nexception thrown!" << endl;
cout << e.what() << endl;
return -5;
}
std::vector<matrix<float, 0, 1>> fsrc = GetFaceFeature(img);
if(fsrc.size() > 1 || fsrc.size() == 0)
return -2;
if(mapFeature.count(strfeatureinfo) == 0)
return -3;
float dis = (float)length(fsrc[0] - mapFeature.at(strfeatureinfo));
if(dis > frthreshold)
return 0;
else
return 1;
}
int fb_insertfeature(const char* picpath)
{
std::string strPicPath = picpath;
if(strPicPath.empty())
return 0;
if(mapFeature.count(strPicPath))
return -1;
matrix<rgb_pixel> img;
try
{
load_image(img, strPicPath);
}
catch(exception& e)
{
cout << "\nexception thrown!" << endl;
cout << e.what() << endl;
return -5;
}
std::vector<matrix<float, 0, 1>> fsrc = GetFaceFeature(img);
if(fsrc.size() > 1 || fsrc.size() == 0)
return -2;
std::string label = fileName.find_last_of('.') == string::npos ? fileName : fileName.substr(0,fileName.find_last_of('.'));
mapFeature.insert(pair<string,matrix<float, 0, 1>>(label,fsrc[0]));
return 1;
}
int fb_deletefeature(const char* featureinfo)
{
string strInfo = featureinfo;
if(strInfo.empty())
return -1;
if(mapFeature.count(strInfo) == 0)
return 0;
mapFeature.erase(strInfo);
return 1;
}
命令行编译
windows
mkdir build
cd build
cmake -G "Visual Studio 14 2015 Win64" -T host=x64 ..
cmake --build . --config Release
linux
mkdir build
cd build
cmake ..
cmake --build . --config Release
链接库测试
linux下可以使用nm命令查看so文件函数列表;windows下使用vs2015命令行下的dumpbin命令查看dll文件的函数列表。
cd 到动态链接库所在文件夹下,输入命令:
windows
dumpbin /exports facerecog.dll
linux
nm libfacerecog.so | grep fg
nm libfacerecog.so | grep fb
demo
frtest.cpp
#include "facerecoglib.h"
#include <string>
#include <iostream>
int main()
{
int res = fg_init("data", 0.4);
if(res > 0)
{
std::cout << "print pic path to recog person" << std::endl;
std::string path;
while(1)
{
std::cin >> path;
std::cout << fg_recog(path.c_str()) << std::endl;
std::cout << "continue print pic path" << std::endl;
}
}
std::cout << res << std::endl;
return 0;
}
编写一个简单的c++demo对动态连接库进行调用测试,demo目录中内容如图
data中保存基准图片,model保存模型,命令行运行frtest,结果如下
参考
机器学习库dlib的C++编译和使用(windows和linux)_踏莎行hyx的博客-CSDN博客_dlib c++
linux环境下利用Cmake生成动态链接库并使用实例_搞技术的火星人的博客-CSDN博客_cmake生成动态库 linux
c++人脸识别-vs2017 + dlib19.19_zzubqh103的博客-CSDN博客_dlib人脸识别c++
更多推荐
已为社区贡献1条内容
所有评论(0)