Dlib+Resnet实现人脸检测/注册/识别

说明

在下封装了一个人类识别类,供大家参考。使用以下代码可以很快的开始你的人脸定位,人脸注册,人脸识别验证。(人脸注册以图片+名字的形式)

使用环境

windows/linux,支持C++11的编译器(msvc14,msvc15+,gcc4.7+)

准备材料

CMake + dlib源码 + opencvdlib_face_recognition_resnet_model_v1.dat + shape_predictor_68_face_landmarks.dat

环境配置

cmake dlib

配置 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人脸定位/识别/年龄预测/性别预测/口罩有无/眼睛睁闭

 

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值