SeetafaceV6人脸定位/识别/年龄预测/性别预测/口罩有无/眼睛睁闭

功能

人脸定位,人脸识别,年龄预测,性别预测,口罩有无,眼睛睁闭识别集一体demo,活体检测效果不佳(可能是我摄像头太渣的原因),没加上。

环境

Windows10,vs2015/2017,seetaface6,opencv411

代码

#include <iostream>
#include <opencv2/opencv.hpp>
#include "seeta/FaceDetector.h"
#include "seeta/FaceLandmarker.h"
#include "seeta/FaceRecognizer.h"
#include "seeta/GenderPredictor.h"
#include "seeta/AgePredictor.h"
#include "seeta/EyeStateDetector.h"
#include "seeta/MaskDetector.h"

using namespace std;
using namespace cv;
#define IS_KEY_Q(k) (k == 113 || k == 81)
#define IS_KEY_R(k) (k == 114 || k == 82)
#define IS_KEY_SPACE(k) (k == 32)

const string TITLE = "人脸识别";
const string FACEDB = "faceDB/";
seeta::FaceDetector *FD = NULL;
seeta::FaceLandmarker *FL = NULL;
seeta::FaceRecognizer *FR = NULL;
seeta::GenderPredictor *GP = NULL;
seeta::AgePredictor *AP = NULL;
seeta::EyeStateDetector *EBD = NULL;
seeta::MaskDetector *MD = NULL;
VideoCapture *CAP = NULL;
Mat FRAME;
Mat REG_FRAME;
vector<std::shared_ptr<float>> FEATURES;
vector<Rect> FACE_RECTS;
vector<std::shared_ptr<float>> FACEDB_FEATURES;
vector<string> FACEDB_NAMES;

void register_face();
void recognize_face();
bool init();
void deinit();
void extract_features();
void extract_feature(Mat img);

int main(int argc, char **argv) {

	bool r = init();
	while (r) {

		CAP->read(FRAME);
		if (FRAME.empty()) continue;
		FRAME.copyTo(REG_FRAME);
		recognize_face();
		imshow(TITLE, FRAME);
		int key = waitKey(10);
		if (IS_KEY_Q(key)) {

			break;
		}
		if (IS_KEY_R(key)) {

			register_face();
		}
	}
	deinit();
	return 0;
}

bool init() {

	cout << "======基于seetaface的人脸识别======" << endl;
	cout << "|Q/q ------------------------ 退出|" << endl;
	cout << "|R/r ------------------------ 注册|" << endl;
	cout << "===================================" << endl;

	cout << "加载模型···" << endl;
	seeta::ModelSetting fd_setting;
	fd_setting.set_device(SEETA_DEVICE_CPU);
	fd_setting.append("models/face_detector.csta");
	FD = new seeta::FaceDetector(fd_setting);

	seeta::ModelSetting fl_setting;
	fl_setting.set_device(SEETA_DEVICE_CPU);
	fl_setting.append("models/face_landmarker_pts5.csta");
	FL = new seeta::FaceLandmarker(fl_setting);

	seeta::ModelSetting fr_setting;
	fr_setting.set_id(0);
	fr_setting.append("models/face_recognizer.csta");
	fr_setting.set_device(SEETA_DEVICE_CPU);
	FR = new seeta::FaceRecognizer(fr_setting);

	seeta::ModelSetting gp_setting("models/gender_predictor.csta");
	GP = new seeta::GenderPredictor(gp_setting);

	seeta::ModelSetting ap_setting("models/age_predictor.csta");
	AP = new seeta::AgePredictor(ap_setting);

	seeta::ModelSetting edb_setting;
	edb_setting.set_device(SEETA_DEVICE_CPU);
	edb_setting.set_id(0);
	edb_setting.append("models/eye_state.csta");
	EBD = new seeta::EyeStateDetector(edb_setting);

	seeta::ModelSetting md_setting;
	md_setting.set_device(SEETA_DEVICE_CPU);
	md_setting.append("models/mask_detector.csta");
	MD = new seeta::MaskDetector(md_setting);

	if (!FD || !FL || !FR || !GP || !AP || !EBD || !MD) {

		cout << "加载模型失败" << endl;
		return false;
	}

	cout << "加载摄像头/本地视频···" << endl;
	namedWindow(TITLE, 1);
	//CAP = new VideoCapture(0);
	CAP = new VideoCapture("qyn.mp4");
	if (!CAP->isOpened()) {

		cout << "加载摄像头/本地视频失败" << endl;
		return false;
	}

	cout << "加载人脸数据库···" << endl;
	vector<cv::String> files;
	glob(FACEDB, files);
	FACEDB_FEATURES.clear();
	FACEDB_NAMES.clear();
	for (int i = 0; i < files.size(); i++) {

		string filename(files[i]);
		Mat f = imread(filename);
		if (!f.empty()) {

			extract_feature(f);
			int pos = filename.find_last_of("\\");
			int pos2 = filename.find_last_of(".");
			filename = filename.substr(pos + 1, pos2 - pos - 1);
			cout << "    [" << i << "] " << filename << endl;
			FACEDB_NAMES.push_back(filename);
		}
	}

	return true;
}

void deinit() {

	if (FD) delete FD;
	if (FL) delete FL;
	if (FR) delete FR;
	if (GP) delete GP;
	if (AP) delete AP;
	if (EBD)delete EBD;
	if (MD) delete MD;
	if (CAP) delete CAP;
	cout << "退出" << endl;
}

void register_face() {

	cout << "======人脸注册======" << endl;
	if (FEATURES.size() == 1) {

		string name;
		cout << "请输入名字:";
		cin >> name;

		string path = FACEDB + name + ".jpg";
		cout << "保存" << name << "到" << path << endl;
		imwrite(path, REG_FRAME);

		extract_feature(REG_FRAME);
		FACEDB_NAMES.push_back(name);
	}
	else {

		if (FEATURES.size() == 0) cout << "未识别到人脸" << endl;
		else cout << "识别人脸数目过多" << endl;
	}
}

void recognize_face() {

	extract_features();
	for (int i = 0; i < FEATURES.size(); i++) {

		for (int j = 0; j < FACEDB_FEATURES.size(); j++) {

			float similar = FR->CalculateSimilarity(FEATURES[i].get(), FACEDB_FEATURES[j].get());
			if (similar > 0.75f) {

				char simch[10];
				sprintf_s(simch, "%.2f", similar);
				putText(FRAME, FACEDB_NAMES[j] + " " + string(simch), Point(FACE_RECTS[i].x, FACE_RECTS[i].y - 10), cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(0, 0, 255), 2);
				break;
			}
		}
	}
}

void extract_features() {

	SeetaImageData simg;
	simg.height = FRAME.rows;
	simg.width = FRAME.cols;
	simg.channels = FRAME.channels();
	simg.data = FRAME.data;
	FEATURES.clear();
	FACE_RECTS.clear();

	auto faces = FD->detect(simg);
	for (int i = 0; i < faces.size; i++) {

		auto face = faces.data[i].pos;
		SeetaPointF points[5];
		FL->mark(simg, faces.data[i].pos, points);
		std::shared_ptr<float> feature(new float[FR->GetExtractFeatureSize()]);
		FR->Extract(simg, points, feature.get());
		FEATURES.push_back(feature);
		FACE_RECTS.push_back(Rect(face.x, face.y, face.width, face.height));

		// detect mask
		float score;
		bool r = MD->detect(simg, face, &score);

		// detect boy/girl
		seeta::GenderPredictor::GENDER gender;
		GP->PredictGenderWithCrop(simg, points, gender);
		
		// detect age
		int age;
		AP->PredictAgeWithCrop(simg, points, age);
		
		// detect eye open/close
		seeta::EyeStateDetector::EYE_STATE leftstate, rightstate;
		EBD->Detect(simg, points, leftstate, rightstate);

		rectangle(FRAME, Rect(face.x, face.y, face.width, face.height), Scalar(0, 255, 255), 2, 8, 0);
		for (int i = 0; i < 5; i++) {

			circle(FRAME, Point(points[i].x, points[i].y), (face.width + face.height) / 50, Scalar(255, 0, 0), -1);
			//putText(FRAME, to_string(i), Point(points[i].x, points[i].y), cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(0, 0, 255), 2);
		}
		string mask_stat = "unmask";
		if (score > 0.8f) mask_stat = "mask";
		putText(FRAME, mask_stat, Point(FACE_RECTS[i].x, FACE_RECTS[i].y + 16), cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(0, 0, 255), 2);
		putText(FRAME, "sex:" + string((gender == 0 ? "boy" : "girl")),
			Point(face.x, face.y + face.height - 10), cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(0, 0, 255), 2);
		putText(FRAME, "age:" + to_string(age), Point(face.x, face.y + face.height - 40), cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(0, 0, 255), 2);
		putText(FRAME, leftstate == seeta::EyeStateDetector::EYE_CLOSE ? "X" : "O", Point(points[0].x, points[0].y), cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(0, 0, 255), 2);
		putText(FRAME, rightstate == seeta::EyeStateDetector::EYE_CLOSE ? "X" : "O", Point(points[1].x, points[1].y), cv::FONT_HERSHEY_COMPLEX, 0.8, cv::Scalar(0, 0, 255), 2);
	}
}

void extract_feature(Mat img) {

	SeetaImageData simg;
	simg.height = img.rows;
	simg.width = img.cols;
	simg.channels = img.channels();
	simg.data = img.data;
	auto faces = FD->detect(simg);
	if (faces.size >= 1) {

		SeetaPointF points[5];
		FL->mark(simg, faces.data[0].pos, points);
		std::shared_ptr<float> feature(new float[FR->GetExtractFeatureSize()]);
		FR->Extract(simg, points, feature.get());
		FACEDB_FEATURES.push_back(feature);
	}
}

效果

 

资源

下载地址:https://pan.baidu.com/s/1-HSEL9PbN_b6GKtFxYYsFg // 密码:ccff

参考

https://github.com/seetafaceengine/SeetaFace6

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值