前言
基于深度学习的人脸识别系统,一共用到了5个开源库:OpenCV(计算机视觉库)、Caffe(深度学习库)、Dlib(机器学习库)、libfacedetection(人脸检测库)、cudnn(gpu加速库)。
用到了一个开源的深度学习模型:VGG model。
最终的效果是很赞的,识别一张人脸的速度是0.039秒,而且最重要的是:精度高啊!!!
CPU:intel i5-4590
GPU:GTX 980
系统:Win 10
OpenCV版本:3.1(这个无所谓)
Caffe版本:Microsoft caffe (微软编译的Caffe,安装方便,在这里安利一波)
Dlib版本:19.0(也无所谓
CUDA版本:7.5
cudnn版本:4
libfacedetection:6月份之后的(这个有所谓,6月后出了64位版本的)
这个系列纯C++构成,有问题的各位朋同学可以直接在博客下留言,我们互相交流学习。
====================================================================
本篇是该系列的第六篇博客,介绍如何设计一个识别类来用于具体的分类任务。
思路
现在我们希望能够有一个识别的接口来实现输入一张图片,便可以分辨出他是哪个人。我们需要提前:
1、定义一个人脸空间;
2、将一些人脸的图片放到这个人脸空间中;
3、将n个人脸图片提取特征为n个向量,并且合并为一个矩阵;
4、将n个人脸图片的标注(label)合并为一个向量,与矩阵形成对应;
5、将其序列化并保存起来,等待识别时进行读取。
在前五篇博客中,我们已经可以很方便的来完成这些事情了。代码如下:
vector<Mat> imgArray;
vector<string> labelArray;
for ( int i = 0; i < 5; i++)//读入5张图片
{
string img_file = "img/" + Int_String(i) + ".jpg";
Mat img = imread(img_file);
imgArray.push_back(img);
labelArray.push_back(img_file);
}
Register Train;
for (int j = 0; j < 5; j++)
Train.JoinFaceSpace(imgArray[j], "MySpace", labelArray[j]);
人脸空间的名字为:MySpace;每一个人脸的名称都用它们的文件路径直接来代替。
我们来看看这五张人脸:
我们来看看保存后的结果:
代码
设计一个类,希望其具有读入训练文件,读入新图片,进行匹配的功能。
Register.h:
class Recognition
{
public:
vector<string> NameVector;
//vector
void LoadVector(string FaceSpace);//读入数据,保存的名称为FaceSpace_FaceVector/FaceSpace_FaceName
void LoadRecognitionModel(vector<vector<float>> FaceMatrix, vector<string> NameVector);//创建识别模型,需要输入FaceMarix,NameVector.
string Predict(Mat LoadGetFace);//预测
//用法: Recognition test; test.LoadRecognitionModel();cout<<test->predict(Mat) ; test.update()
void clear();
void update(vector<vector<float>> FaceMatrix, vector<string> NameVector);//change .
vector<vector<float>> FaceMat;
private:
vector <vector<float>> ReadVector (string FaceSpace);//input FaceSpace ,read to get vector <vector<float>>
};
函数的具体代码:
Register.cpp:
void Recognition::LoadVector(string FaceSpace) // save the people's face vector
{
string FaceVectorRoad = "data/" + FaceSpace + "_FaceMatrix.xml";
string NameVectorRoad = "data/" + FaceSpace + "_NameVector.txt";
vector<vector<float> > FaceVector;
FaceVector = LoadFaceMatrix(FaceVectorRoad);
NameVector=LoadNameVector(NameVector, NameVectorRoad);
if (!FaceVector.empty() && !NameVector.empty())
{
FaceMat = FaceVector;
NameVector = NameVector;
cout << "Sucessfully read the FaceSpace:" + FaceSpace + "'s data!" << endl;
}
else { cout << "There is no data in this FaceSpace:" + FaceSpace + ",Please input ." << endl; }
}
string Recognition::Predict(Mat LoadGetFace)//可优化,using CUDA TO COMPUTE
{
if (!LoadGetFace.empty())
{
vector<float> v = ExtractFeature(FaceDetect(LoadGetFace));
if (!v.empty())
{
int ID = -1;
float MaxCos = 0;
for (int i = 0; i < NameVector.size(); i++)
{
float t_cos = cosine(v, FaceMat[i]);
if (t_cos > MaxCos)
{
ID = i;
MaxCos = t_cos;//update the coff
}
}
return NameVector[ID];
}
else
{
cout << "The Picture does not have people's Face,Please try again." << endl;
}
}
else cout << "The picture is empty.Please Check it and make sure." << endl;
}
void Recognition::LoadRecognitionModel(vector<vector<float>> FaceMatrix, vector<string> NameVector_)//创建识别模型,需要输入FaceMarix,NameVector.
{
if (!FaceMatrix.empty() &&!NameVector_.empty())
{
FaceMat = FaceMatrix;
NameVector = NameVector_;
}
else
{
cout << "Please check your FaceMatrix and NameVector.It may be empty." << endl;
}
}
void Recognition::clear()
{
FaceMatrix_ = NULL;
NameVector.clear();
}
void Recognition::update(vector<vector<float>> FaceMatrix, vector<string> NameVector)
{
clear_();
LoadRecognitionModel(FaceMat, NameVector);
}
得益于前几篇里我们已经建立好的接口,那么在主函数里,就只需几行即可。
Recognition Val;
Val.LoadVector("MySpace");
Val.LoadRecognitionModel(Val.FaceMat, Val.NameVector);
Mat test = imread("test.jpg");
cout << "图片对应的训练样本为: ";
cout<<Val.Predict(test)<<endl;
imshow("Face Recognition", test);
waitKey(0);
运行看看结果:
匹配是完全正确的。(可以看看注册时候的几张图片,对比一下)
至此,实现一个人脸识别任务的主要手段已经都完成了。接下来的几篇将从如何美化程序界面,如何加速人脸匹配速度来入手。如果可能的话,后面还可以写一下怎么微调这个神经网络让其在自己的数据集上来进行更高精度的识别。
=================================================================