该项目根据官方代码改编。
-
准备模型,下载地址
shape_predictor_5_face_landmarks.dat
dlib_face_recognition_resnet_model_v1.dat -
创建项目,引入dlib和opencv,CMakeLists.txt代码
cmake_minimum_required(VERSION 2.8)
project(myfaceRecognition)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O2")
IF(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything")
ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
ENDIF()
find_package(OpenCV 4.2.0 REQUIRED)
find_package(dlib REQUIRED)
include_directories(${dlib_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} "main.cpp")
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OpenCV_LIBS} ${dlib_LIBRARIES})
- main.cpp 代码
#include <dlib/dnn.h>
#include <dlib/gui_widgets.h>
#include <dlib/clustering.h>
#include <dlib/string.h>
#include <dlib/image_io.h>
#include <dlib/image_transforms.h>
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <unistd.h>
#include <dirent.h>
#include <string>
#include <opencv2/opencv.hpp>
using namespace dlib;
using namespace std;
using namespace cv;
//神经网络固定模板
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>
>>>>>>>>>>>>;
// ----------------------------------------------------------------------------------------
static cv::Rect dlibRectangleToOpenCV(dlib::rectangle r)
{
return cv::Rect(cv::Point2i(r.left(), r.top()), cv::Point2i(r.right() + 1, r.bottom() + 1));
}
std::vector<string> getFiles(string cate_dir);
int main(int argc, char** argv) try
{
if (argc != 2)
{
cout << "Run this example by invoking it like this: " << endl;
cout << " ./myfaceRecognition faces/" << endl;
cout << endl;
return 1;
}
// 加载人脸检测模型
frontal_face_detector detector = get_frontal_face_detector();
// 加载人脸矫正模型
shape_predictor sp;
deserialize("shape_predictor_5_face_landmarks.dat") >> sp;
// 加载人脸编码模型
anet_type net;
deserialize("dlib_face_recognition_resnet_model_v1.dat") >> net;
// 从图片文件夹获取人脸编码
std::vector<string> filenames = getFiles(argv[1]);
std::vector<std::pair<matrix<float,0,1>,string>> codeToName;
for(size_t i = 0; i < filenames.size(); i++)
{
matrix<rgb_pixel> img;
load_image(img, filenames[i]);
std::vector<matrix<rgb_pixel>> faces;
for (auto face : detector(img))
{
auto shape = sp(img, face);
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));
}
if(faces.size() == 0)
{
continue;
}
// 编码
std::vector<matrix<float,0,1>> face_descriptors = net(faces);
// 提取文件名
int pos = filenames[i].find_last_of('//');
string sfilename(filenames[i].substr(pos + 1));
pos = sfilename.find_last_of('.');
string sfilenameEx(sfilename.substr(0,pos));
for(size_t i = 0; i < face_descriptors.size(); i++)
{
codeToName.push_back(make_pair(face_descriptors[i],sfilenameEx));
}
}
// 获取相机人脸并对比
VideoCapture cap;
cap.open(0);
cap.set(3,640);
cap.set(4,480);
if(!cap.isOpened())
{
cout << "camera is open failed!" << endl;
return -1;
}
Mat frame;
while(cap.read(frame))
{
if(frame.empty())
{
cout << "image is empty" << endl;
break;
}
flip(frame,frame,1);
matrix<dlib::rgb_pixel> image;
dlib::assign_image(image,dlib::cv_image<dlib::rgb_pixel>(frame));
std::vector<matrix<rgb_pixel>> faces;
for (auto face : detector(image))
{
auto shape = sp(image, face);
matrix<rgb_pixel> face_chip;
extract_image_chip(image, get_face_chip_details(shape,150,0.25), face_chip);
matrix<float,0,1> encode = net(face_chip);
//faces.push_back(move(face_chip));
for(size_t j = 0; j < codeToName.size(); j++)
{
if (length(encode - codeToName[j].first) < 0.6f)
{
Rect rect = dlibRectangleToOpenCV(face);
cv::rectangle(frame,rect.tl(),rect.br(),Scalar(0,255,0),2);
cv::putText(frame, codeToName[j].second, cv::Point(rect.tl().x, rect.tl().y - 1), cv::FONT_HERSHEY_PLAIN, 1.2, cv::Scalar(0xFF, 0xFF, 0xFF), 2);
break;
}
}
}
imshow("image",frame);
if(waitKey(10) == 27)
break;
}
return 0;
}
catch(std::exception& e)
{
cout << e.what() << endl;
}
std::vector<string> getFiles(string cate_dir)
{
std::vector<string> files;//存放文件名
DIR *dir;
struct dirent *ptr;
if ((dir=opendir(cate_dir.c_str())) == nullptr)
{
perror("Open dir error...");
exit(1);
}
while ((ptr=readdir(dir)) != nullptr)
{
if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) ///current dir OR parrent dir
continue;
if(ptr->d_type == 8) ///文件夹
{
files.push_back(cate_dir + "/" + ptr->d_name);
}
else if(ptr->d_type == 4) ///文件
{
std::vector<string> childfiles = getFiles(cate_dir + "/" + ptr->d_name);
files.insert(files.end(),childfiles.begin(),childfiles.end());
}
}
closedir(dir);
return files;
}
- 编译运行,注意faces文件夹内图片d的命名
mkdir build
cd build & mkdir faces
cmake ..
make
./myfaceRecognition faces/