how to use seeta face engine to detect and recognize face

Author: kagula

Date: 2017-09-18

Environment:

[1]VS20217 Update3

[2]Seeta face engine

[3]opencv-2.4.13.3

[4]boost 1.64


introduction

   a seeta face engine demo. 

   note face identification depends  face alignment and face detection.


Content:

kagula.h

#ifndef _KAGULA_H_
#define _KAGULA_H_

#include <string>

namespace kagula
{
	class seetaFace
	{
	public:
		//初始化整个模块
		void init();

		//如果没有匹配返回.0f,否则返回匹配程度。
		float bestMatch(const std::string srcFileName, const std::string dstFileName,std::string &outputFileName);
	};
}

#endif


kagula.cpp

#include "kagula.h"

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;


#include <boost/shared_ptr.hpp>

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

#include "face_detection.h"
#include "face_alignment.h"
#include "face_identification.h"

//seeta的三个class不能直接用boost智能指针,所以。。。 。。。
seeta::FaceDetection gDetector("seeta\\seeta_fd_frontal_v1.0.bin");//人脸检测
seeta::FaceAlignment gPointDetector("seeta\\seeta_fa_v1.1.bin");//landmark points(left eye, right eye, nose, left and right corner of mouth)
seeta::FaceIdentification gFaceRecognizer("seeta\\seeta_fr_v1.0.bin");

namespace kagula
{
	struct FacialFeature
	{
		string fileName;//匹配的子图象,临时文件名。
		float* pFeature;
		cv::Mat image;//匹配的子图象
		float similarity;

		FacialFeature() :similarity(.0f)
		{
			pFeature = new float[gFaceRecognizer.feature_size()];
		}

		~FacialFeature()
		{
			if (pFeature != nullptr)
				delete pFeature;
		}
	};//struct
}

//D:\SDK\swigwin-3.0.12\Lib\csharp
void initSeetaface();
void GetFacialFeatures(const string &imageFileName, const int unsigned diagonal,
	const string &prefixFileName,
	vector< boost::shared_ptr<kagula::FacialFeature>> &vecFF);
boost::shared_ptr<kagula::FacialFeature> GetBestMatched(vector<boost::shared_ptr<kagula::FacialFeature>> &vecFF,
	boost::shared_ptr<kagula::FacialFeature> ffDest);
//
namespace kagula
{

	//encapsulate for csharp.begin
	void seetaFace::init()
	{
		initSeetaface();
	}


	float seetaFace::bestMatch(const std::string srcFileName, const std::string dstFileName,
		std::string &outputFileName)
	{
		//含多个头像的图片
		//string imageFileName("D:\\SDK\\FaceRec-2-vs2015 - 副本\\images\\IMG_20160527_074213.jpg");
		int unsigned diagonal = 1000;
		vector<boost::shared_ptr<kagula::FacialFeature>> vecFF;
		string prefix = "debug";
		GetFacialFeatures(srcFileName, diagonal, prefix, vecFF);

		//含一个头像的图片
		//string imageFileName2("D:\\workspace\\TestSeetaFace\\temp\\a.jpg");
		int unsigned diagonal2 = 250;
		vector< boost::shared_ptr<kagula::FacialFeature>> vecFF2;

		string prefix2 = "debug2";
		GetFacialFeatures(dstFileName, diagonal2, prefix2, vecFF2);

		if (vecFF.size() > 0 && vecFF2.size() == 1)
		{
			//打印出最匹配的头像
			boost::shared_ptr<kagula::FacialFeature> bestMatched = GetBestMatched(vecFF, vecFF2[0]);
			outputFileName = bestMatched->fileName;
			return bestMatched->similarity;
		}
		return .0f;
	}
	//encapsulate for csharp.end
}//namespace



void initSeetaface()
{
	gDetector.SetMinFaceSize(40);//设置的越小检测时间越长,但是小脸也可以检测到
	gDetector.SetScoreThresh(2.f);
	gDetector.SetImagePyramidScaleFactor(0.8f);
	gDetector.SetWindowStep(4, 4);
}

void GetFacialFeatures(const string &imageFileName, const int unsigned diagonal,
	const string &prefixFileName,
	vector< boost::shared_ptr<kagula::FacialFeature>> &vecFF)
{
	//resize image
	cv::Mat img0 = cv::imread(imageFileName.c_str());
	if (img0.empty())
		return;


	float scale = 1.0f;
	float newh = img0.rows;
	float neww = img0.cols;
	if (img0.rows*img0.cols > 200*200)
	{
		//如果图片太大,缩小之。
		float scale = float(diagonal) / (img0.rows + img0.cols);
		float newh = scale * img0.rows;
		float neww = scale * img0.cols;
	}
	cv::Mat img1;
	resize(img0, img1, cv::Size(neww, newh), 0, 0, CV_INTER_LINEAR);

	//to gray image
	cv::Mat img_gray;
	cv::cvtColor(img1, img_gray, CV_BGR2GRAY);

	//seeta gray image object//这是给identity用的。
	seeta::ImageData seeta_img_color(img1.cols, img1.rows, img1.channels());
	seeta_img_color.data = img1.data;

	//seeta gray image object//这是给detect用的。
	seeta::ImageData seeta_img_gray(img_gray.cols, img_gray.rows, img_gray.channels());
	seeta_img_gray.data = img_gray.data;

	// Detect faces
	std::vector<seeta::FaceInfo> faces = gDetector.Detect(seeta_img_gray);
	if ( faces.size() == 0 )
	{
		cout << "未检测到人脸" << endl;
	}
	else
	{
		cout << "检测到人脸[" << faces.size() << "]" << endl;

		for (int32_t i = 0; i <faces.size(); i++) {
			//把检测到的人脸profile用Rectangle标出来!
			cv::Rect face_rect;
			face_rect.x = faces[i].bbox.x;
			face_rect.y = faces[i].bbox.y;
			face_rect.width = faces[i].bbox.width;
			face_rect.height = faces[i].bbox.height;
			cv::rectangle(img1, face_rect, CV_RGB(0, 0, 255), 4, 8, 0);//blue

																	   //把人脸的5个landmark points(left eye, right eye, nose, left and right corner of mouse)标出来
			seeta::FacialLandmark points[5];
			gPointDetector.PointDetectLandmarks(seeta_img_gray, faces[i], points);
			/* 方便人眼识别
			for (int j = 0; j<5; j++)
			{
				cv::circle(img1, cvPoint(points[j].x, points[j].y), 2, CV_RGB(0, 255, 0), CV_FILLED);//green
			}
			*/

			//Extract face identity feature  
			boost::shared_ptr<kagula::FacialFeature> pFF(new kagula::FacialFeature());
			face_rect.x = face_rect.x < 0 ? 0 : face_rect.x;
			face_rect.y = face_rect.y < 0 ? 0 : face_rect.y;
			face_rect.x = face_rect.x >= img1.size().width ? img1.size().width-1 : face_rect.x;
			face_rect.y = face_rect.y >= img1.size().height ? img1.size().height - 1 : face_rect.y;

			face_rect.width = face_rect.width + face_rect.x > img1.size().width ? img1.size().width - face_rect.x : face_rect.width;
			face_rect.height = face_rect.height + face_rect.y > img1.size().height ? img1.size().height - face_rect.y: face_rect.height;
			if (face_rect.width > 0 && face_rect.height > 0)
			{
				pFF->image = img1(face_rect);//crop region from img1 instance.
				gFaceRecognizer.ExtractFeatureWithCrop(seeta_img_color, points, pFF->pFeature);
				vecFF.push_back(pFF);
			}
		}//every facial part.

		 //for debug,output temporary images.
		 //D:\workspace\TestSeetaFace\TestSeetaFace
		stringstream ss;
		ss << prefixFileName << "_completeTemporaryPicture.jpg";
		cv::imwrite(ss.str(), img1);
		int k = 1;
		for (vector< boost::shared_ptr<kagula::FacialFeature>>::iterator iter = vecFF.begin();
			iter != vecFF.end(); k++, iter++)
		{
			stringstream ss;
			ss << prefixFileName << "_subimage_" << k << ".jpg";
			(*iter)->fileName = ss.str();
			cv::imwrite(ss.str(), (*iter)->image);
		}
	}
}

bool SortCompare(boost::shared_ptr<kagula::FacialFeature> src, boost::shared_ptr<kagula::FacialFeature> dest)
{
	return src->similarity > dest->similarity;
}

boost::shared_ptr<kagula::FacialFeature> GetBestMatched(vector<boost::shared_ptr<kagula::FacialFeature>> &vecFF,
	boost::shared_ptr<kagula::FacialFeature> ffDest)
{
	for (int i = 0; i < vecFF.size(); i++)
	{
		vecFF[i]->similarity = gFaceRecognizer.CalcSimilarity(vecFF[i]->pFeature, ffDest->pFeature);
#ifdef _DEBUG
		cout << "similarity=" << vecFF[i]->similarity << ",src=" << vecFF[i]->pFeature << ",dest=" << ffDest->pFeature << endl;
#endif // DEBUG
	}

	//nth_element对给定范围进行"排序"
	std::nth_element(vecFF.begin(), vecFF.begin() + 1, vecFF.end(), SortCompare);//对cosdis排序,求得最高的[需要对比阈值]返回SRClabel

	return vecFF[0];
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kagula086

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值