说明
在下封装了一个人类识别类,供大家参考。使用以下代码可以很快的开始你的人脸定位,人脸注册,人脸识别验证。(人脸注册以图片+名字的形式)
使用环境
windows/linux,支持C++11的编译器(msvc14,msvc15+,gcc4.7+)
准备材料
CMake + dlib源码 + opencv + dlib_face_recognition_resnet_model_v1.dat + shape_predictor_68_face_landmarks.dat
环境配置
配置 dlib+opencv环境
下载dlib_face_recognition_resnet_model_v1.dat + shape_predictor_68_face_landmarks.dat
源代码
KcgFR.h
#ifndef _KCG_FR_H_
#define _KCG_FR_H_
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing/render_face_detections.h>
#include <dlib/image_processing.h>
#include <dlib/gui_widgets.h>
#include <dlib/dnn.h>
#include <dlib/clustering.h>
#include <dlib/string.h>
#include <dlib/image_io.h>
#include <opencv2/opencv.hpp>
class KcgFR {
public:
typedef struct FaceDescribe_S {
cv::Rect rect;
std::string name = "";
float similarity = 0.f;
std::vector<cv::Point> marks;
dlib::matrix<dlib::rgb_pixel> face;
dlib::matrix<float, 0, 1> desc;
}FaceDescribe;
typedef std::vector<FaceDescribe> FaceDescribes;
public:
KcgFR(const std::string landmark_file, const std::string resnet_file);
~KcgFR();
int FaceLocate(cv::Mat &f, FaceDescribes &descs);
int FaceLocate(cv::Mat f, cv::Mat &draw_f, cv::Scalar color = cv::Scalar(255, 0, 0), int thk = 1);
bool FaceReg(FaceDescribe desc, std::string name);
bool FaceReg(cv::Mat &f, std::string name); /// 注意:被draw过的图像不能传进来
int FaceRecognize(FaceDescribes &descs, float similarity = 0.6f);
int FaceRecognize(cv::Mat &f, float similarity = 0.6f,
cv::Scalar color = cv::Scalar(255, 0, 0), int thk = 1);
void FaceDraw(cv::Mat &f, FaceDescribes descs, cv::Scalar color, int thk);
private:
dlib::frontal_face_detector detector_;
dlib::shape_predictor sp_;
FaceDescribes face_descs_;
};
#endif
KcgFR.cpp
#include "KcgFR.h"
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>
>>>>>>>>>>>>;
anet_type net_;
KcgFR::KcgFR(const std::string landmark_file, const std::string resnet_file) {
detector_ = get_frontal_face_detector();
deserialize(landmark_file) >> sp_;
deserialize(resnet_file) >> net_;
}
KcgFR::~KcgFR() {
}
int KcgFR::FaceLocate(cv::Mat &f, FaceDescribes &descs) {
descs.clear();
dlib::cv_image<rgb_pixel> dlib_img(f);
std::vector<dlib::rectangle> rects = detector_(dlib_img);
std::vector<full_object_detection> shapes;
shapes.clear();
int face_number = (int)rects.size();
for (int i = 0; i < face_number; i++) {
auto shape = sp_(dlib_img, rects[i]);
shapes.push_back(shape);
matrix<rgb_pixel> face_chip; // face roi
extract_image_chip(dlib_img, get_face_chip_details(shape, 150, 0.25), face_chip);
std::vector<cv::Point> marks;
marks.clear();
for (int j = 0; j < 68; j++) {
cv::Point pt = cv::Point(shapes[i].part(j).x(), shapes[i].part(j).y());
marks.push_back(pt);
}
FaceDescribe desc;
desc.rect = cv::Rect(rects[i].left(), rects[i].top(),
rects[i].width(), rects[i].height());
desc.name = "";
desc.similarity = 0.f;
desc.marks = marks;
desc.face = move(face_chip);
descs.push_back(desc);
}
return face_number;
}
int KcgFR::FaceLocate(cv::Mat f, cv::Mat &draw_f, cv::Scalar color, int thk) {
f.copyTo(draw_f);
FaceDescribes descs;
int n = FaceLocate(draw_f, descs);
FaceDraw(draw_f, descs, color, thk);
return n;
}
bool KcgFR::FaceReg(FaceDescribe desc, std::string name) {
std::vector<dlib::matrix<dlib::rgb_pixel>> faces;
faces.clear();
faces.push_back(desc.face);
std::vector<matrix<float, 0, 1>> face_descriptors = net_(faces);
// 注册
desc.desc = face_descriptors[0];
desc.name = name;
face_descs_.push_back(desc);
///
//cout << name << endl;
//cout << trans(face_descriptors[0]) << endl;
///
return (face_descriptors[0].size() == 128);
}
bool KcgFR::FaceReg(cv::Mat &f, std::string name) {
FaceDescribes descs;
int n = FaceLocate(f, descs);
if (n == 1) {
FaceReg(descs[0], name);
return true;
}
return false;
}
int KcgFR::FaceRecognize(FaceDescribes &descs, float similarity) {
std::vector<dlib::matrix<dlib::rgb_pixel>> faces;
faces.clear();
for (int i = 0; i < descs.size(); i++) {
faces.push_back(descs[i].face);
}
std::vector<matrix<float, 0, 1>> face_descriptors = net_(faces);
float dist_err = 1.f - similarity;
int rz_num = 0;
for (int i = 0; i < face_descriptors.size(); i++) {
float min_err = 100.f;
int idx = 0;
for (int j = 0; j < face_descs_.size(); j++) {
float err = (float)length(face_descriptors[i] - face_descs_[j].desc);
if (err < min_err) {
min_err = err;
idx = j;
}
}
if (min_err <= dist_err) {
descs[i].name = face_descs_[idx].name;
descs[i].similarity = 1.f - min_err;
++rz_num;
}
else {
descs[i].name = "?";
descs[i].similarity = 0.f;
}
}
return rz_num;
}
int KcgFR::FaceRecognize(cv::Mat &f, float similarity, cv::Scalar color, int thk) {
FaceDescribes descs;
FaceLocate(f, descs);
int rz_num = FaceRecognize(descs, similarity);
FaceDraw(f, descs, color, thk);
return rz_num;
}
void KcgFR::FaceDraw(cv::Mat &f, FaceDescribes descs, cv::Scalar color, int thk) {
for (int i = 0; i < descs.size(); i++) {
cv::rectangle(f, descs[i].rect, color, thk);
if (descs[i].similarity > 0.f) {
char text[64];
sprintf_s(text, "%s,%.2f", descs[i].name.c_str(), descs[i].similarity);
cv::putText(f, text, cv::Point(descs[i].rect.x, descs[i].rect.y),
cv::FONT_HERSHEY_COMPLEX, 0.6, color, 1);
}
for (int j = 0; j < descs[i].marks.size(); j++) {
cv::circle(f, descs[i].marks[j], 1, color, -1);
}
}
}
运行效果
更多
《SeetafaceV6人脸定位/识别/年龄预测/性别预测/口罩有无/眼睛睁闭》