#include "FaceRecognition.h"
#include <facedetect-dll.h>
#include <Windows.h>
#include <sstream>
#pragma comment(lib,"libfacedetect-x64.lib")
#define DETECT_BUFFER_SIZE 0x20000
namespace caffe
{
extern INSTANTIATE_CLASS(InputLayer);
extern INSTANTIATE_CLASS(InnerProductLayer);
extern INSTANTIATE_CLASS(DropoutLayer);
extern INSTANTIATE_CLASS(ConvolutionLayer);
REGISTER_LAYER_CLASS(Convolution);
extern INSTANTIATE_CLASS(ReLULayer);
REGISTER_LAYER_CLASS(ReLU);
extern INSTANTIATE_CLASS(PoolingLayer);
REGISTER_LAYER_CLASS(Pooling);
extern INSTANTIATE_CLASS(LRNLayer);
REGISTER_LAYER_CLASS(LRN);
extern INSTANTIATE_CLASS(SoftmaxLayer);
REGISTER_LAYER_CLASS(Softmax);
extern INSTANTIATE_CLASS(ConcatLayer);
//REGISTER_LAYER_CLASS(Concat);
extern INSTANTIATE_CLASS(MemoryDataLayer);
extern INSTANTIATE_CLASS(EltwiseLayer);
//REGISTER_LAYER_CLASS(Eltwise);
extern INSTANTIATE_CLASS(PowerLayer);
//REGISTER_LAYER_CLASS(Power);
extern INSTANTIATE_CLASS(SplitLayer);
//REGISTER_LAYER_CLASS();
extern INSTANTIATE_CLASS(BatchNormLayer);
//REGISTER_LAYER_CLASS(BatchNorm);
extern INSTANTIATE_CLASS(ScaleLayer);
extern INSTANTIATE_CLASS(BiasLayer);
extern INSTANTIATE_CLASS(PReLULayer);
extern INSTANTIATE_CLASS(AccuracyLayer);
extern INSTANTIATE_CLASS(SoftmaxWithLossLayer);
}
FaceRecognition::FaceRecognition()
{
net = new caffe::Net<float>("deepId_deploy.prototxt", caffe::TEST);
net->CopyTrainedLayersFrom("_iter_70000.caffemodel");
memory_layer = (caffe::MemoryDataLayer<float> *)net->layers()[0].get();
}
FaceRecognition::~FaceRecognition()
{
}
bool FaceRecognition::generateFaceBase(std::vector<std::string> files)
{
//人脸库创建来源是硬盘上的单照文件,所以不需要对照片进行缩放处理
//标签名即存放为文件名
cv::Rect roi;//创建感兴趣区域,便于进行图像切割和处理
for (int i = 0; i < files.size(); i++)
{
//对人脸库的每一张人脸照片进行特征扫描并记录
cv::Mat frame;
frame = cv::imread(files[i].c_str());
if (detectSingleFace(frame,roi))
{
//如果检测到人脸,此处只会有一张人脸
cv::Mat img_224 = frame(roi);//根据得到的感兴趣区域,从原图中截取出来,并保存成224*224的图片
//cv::cvtColor(img_224, img_224, CV_BGR2GRAY);
resize(img_224, img_224, cv::Size(224, 224));
//获取人脸库标签(以文件名为标签)
int pos = files[i].find_last_of('\\');
std::string label = files[i].substr(pos + 1);
//存储进入人脸库
SingleFace tempface;
tempface.sourceImage = frame;
tempface.position = roi;
tempface.Roi_224 = img_224;
auto feature_ = extractFeature(tempface.Roi_224);
tempface.feature = feature_;
tempface.label = label;
FaceBase.push_back(tempface);
std::thread t2(&FaceRecognition::StoreFace, this, i);
t2.detach();
}
else
{
printf("no base face detected!!\n");
return false;
}
}
return true;
}
bool FaceRecognition::generateFaceArray(cv::Mat input)
{
int scale;//图片检索前图像缩放比例
cv::Mat smallImg; //存放缩放只后的待检索图片
std::vector<cv::Rect> rois; //对图片检索后存储所有感兴趣区域(所有人脸)
scale = imgScale(input, smallImg);
//printf("scale=%d", scale);
if (detectMultiFace(smallImg,scale,rois))
{
m_nFaceArraySize = rois.size();
for (int i = 0; i < rois.size(); i++)
{
//对于每一张检测出来的脸,都在原图上进行图像切割,并进行大小重定义
cv::Mat img_224 = input(rois[i]);//根据得到的感兴趣区域,从原图中截取出来,并保存成224*224的图片
//cv::cvtColor(img_224, img_224, CV_BGR2GRAY);
cv::resize(img_224, img_224, cv::Size(55, 55));
//存储进入检索人脸组
SingleFace tempface;
tempface.sourceImage = input;
tempface.position = rois[i];
tempface.Roi_224 = img_224;
//auto feature_ = extractFeature(tempface.Roi_224);
//tempface.feature = feature_;
FaceArray.push_back(tempface);
std::thread t1(&FaceRecognition::StoreFaces, this, i);
t1.detach();
//rectangle(smallImg, cv::Rect((rois[i].x / scale), (rois[i].y / scale), (rois[i].width / scale), (rois[i].height / scale)), cv::Scalar(0, 255, 0));
//imshow("缩放后图片", smallImg);
//imshow(s, img_224);
//cv::waitKey();
}
}
else
{
printf("no face detected!!!!!!\n");
return false;
}
return true;
}
//多线程启动,用于将检索人脸信息写入人脸集合
void FaceRecognition::StoreFaces(int index)
{
//互斥写入人脸集合
thread_mutex1.lock();
//auto feature = ExtractFeature(m_vecFaceArray[index].Roi_224);
FaceArray[index].feature = extractFeature(FaceArray[index].Roi_224);
m_nFaceArraySize--;
thread_mutex1.unlock();
}
//多线程启动,用于将带标签人脸库信息写入人脸集合
void FaceRecognition::StoreFace(int index)
{
//互斥写入人脸库
thread_mutex2.lock();
//auto feature = extractFeature(FaceBase[index].Roi_224);
FaceBase[index].feature = extractFeature(FaceBase[index].Roi_224);
m_nFaceBaseSize--;
thread_mutex2.unlock();
}
std::vector<float> FaceRecognition::extractFeature(cv::Mat face_224)
{
thread_mutex3.lock();
std::vector<cv::Mat> test{ face_224 };
std::vector<int> testLabel{ 0 };
memory_layer->AddMatVector(test, testLabel);// memory_layer and net , must be define be a global variable.
std::vector<caffe::Blob<float>*> input_vec;
net->Forward(input_vec);
auto fc7 = net->blob_by_name("fc160");//提取fc7层!4096维特征
float* begin = fc7->mutable_cpu_data();
std::vector<float> feature{ begin, begin + fc7->channels() };
//cout << fc7->channels();
thread_mutex3.unlock();
return move(feature);
}
SingleFace FaceRecognition::recognizeFaces(SingleFace singleface)
{
//输入人脸库照片,与人脸检索照片对比,得到结果
int size_ = FaceArray.size();//获取人脸检索的数量
//获取单张人脸库的特征向量位置
float *single_feature = &singleface.feature[0];
//得到特征向量的维度
int single_channel = singleface.feature.size();
std::vector<double> like_array;//计算检索人脸与人脸库每张照片的相似度,取相似度最高的一个
for (int i = 0; i < size_; i++)
{
float *faces_feature = &FaceArray[i].feature[0];//人脸库里面的特征
like_array.push_back(likeValue(single_feature, faces_feature, single_channel));
}
std::vector<double>::iterator biggest = std::max_element(std::begin(like_array), std::end(like_array));
int max_ = distance(std::begin(like_array), biggest);
printf("匹配度为%f\n", *biggest);
return FaceArray[max_];//返回匹配的特征脸
}
bool FaceRecognition::detectSingleFace(cv::Mat input, cv::Rect &roi)
{
cv::Mat gray;
cv::cvtColor(input, gray, CV_BGR2GRAY);//转成灰度图
int * pResults = NULL;
unsigned char * pBuffer = (unsigned char *)malloc(DETECT_BUFFER_SIZE);//分配缓冲计算空间
if (!pBuffer)
{
fprintf(stderr, "Can not alloc buffer.\n");
return false;
}
int doLandmark = 1; //特征点检测模式
pResults = facedetect_multiview_reinforce(pBuffer, (unsigned char*)(gray.ptr(0)), gray.cols, gray.rows, (int)gray.step, 1.05f, 3, 2, 0, doLandmark);
//printf("%d faces detected.\n", (pResults ? *pResults : 0));//显示检测到的人脸数量(人脸库为1)
//需要获取人脸大小及位置,不需要对特征进行标记
int face_num = (pResults ? *pResults : 0);
if (face_num == 0)
{
printf("no face detected");
return false;
}
cv::Mat result_multiview_reinforce = input.clone();//只用来显示人脸图像而已
//获取人脸位置坐标
short * p = ((short*)(pResults + 1));
int x = p[0];
int y = p[1];
int w = p[2];
int h = p[3];
roi = cv::Rect(x, y, w, h);
//rectangle(result_multiview_reinforce, cv::Rect(x, y, w, h), cv::Scalar(0, 255, 0));
//imshow("result_multiview_reinforce", result_multiview_reinforce);
//cv::waitKey();
free(pBuffer);//释放空间,每次都重新分配
return true;
}
bool FaceRecognition::detectMultiFace(cv::Mat input, int scale, std::vector<cv::Rect> &rois)
{
cv::Mat gray;
cv::cvtColor(input, gray, CV_BGR2GRAY);//转成灰度图
int * pResults = NULL;
unsigned char * pBuffer = (unsigned char *)malloc(DETECT_BUFFER_SIZE);//分配缓冲计算空间
if (!pBuffer)
{
fpri