EmguCV学习笔记 C# 10.2 人脸识别 FaceRecgnizer类
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。
教程VB.net版本请访问:EmguCV学习笔记 VB.Net 目录-CSDN博客
教程C#版本请访问:EmguCV学习笔记 C# 目录-CSDN博客
笔者的博客网址:https://blog.csdn.net/uruseibest
教程配套文件及相关说明以及如何获得pdf教程和代码,请移步:EmguCV学习笔记
学习VB.Net知识,请移步: vb.net 教程 目录_vb中如何用datagridview-CSDN博客
学习C#知识,请移步:C# 教程 目录_c#教程目录-CSDN博客
10.2 人脸识别 FaceRecgnizer类
FaceRecognizer类是EmguCV中用于人脸识别的一个重要类。
FaceRecognizer类是一个抽象类,用于定义人脸识别的基本接口和方法。它包含以下两个重要方法(详细请参看10.2.1节【 LBPHFaceRecgnizer类】):
1、Train方法
该方法用于训练人脸识别模型。
2、Predict方法
该方法用于对指定图像进行人脸识别,并返回识别结果。
通常,使用FaceRecognizer类进行人脸识别的具体步骤如下:
1. 准备训练数据:首先,需要准备一组已知的人脸图像,用于训练模型。这些图像需要具有代表性,包含各种不同的人脸姿态、表情和光照条件等。
2. 进行训练:使用train方法将训练数据传入FaceRecognizer类中进行训练。训练过程中,该类会计算出训练数据的特征向量、特征值、标签和均值等信息,并生成一个人脸识别模型。
3. 进行预测:使用predict方法将待识别的人脸图像传入FaceRecognizer类中进行预测。该方法会计算出输入图像的特征向量,并将其与训练数据中的特征向量进行比较,以确定预测结果。
4. 获取预测结果:predict方法返回一个PredictionResult结构对象。通过PredictionResult结构可以获得表示预测结果的标签和表示输入图像与匹配的训练数据之间的距离值。
10.2.1 LBPHFaceRecgnizer类
LBPHFaceRecognizer是基于局部二值模式直方图的人脸识别方法。它将人脸图像分成若干个小区域,并对每个小区域计算局部二值模式直方图。然后将所有小区域的直方图串联起来,得到整幅图像的局部二值模式直方图。
在使用LBPHFaceRecognizer类进行人脸识别时,需要先进行训练。训练过程中,需要将一组已知的人脸图像传入该类的train方法中,以便该类能够学习这些人脸图像的特征。一旦训练完成,就可以使用predict方法来预测输入图像中的人脸是否匹配已知的训练数据。
LBPHFaceRecgnizer的主要方法:
1、构造函数如下:
public LBPHFaceRecognizer(
int radius = 1,
int neighbors = 8,
int gridX = 8,
int gridY = 8,
double threshold = 1.79769313486232E+308
)
参数说明:
- radius:用于控制LBP算法中像素采样的像素半径大小。
- neighbors:邻居数,用于控制LBP算法中需要比较的像素点数量。
- gridX、gridY:表示将图像分成的小区域的行数和列数。
- Threshold:表示识别结果的阈值,如果识别结果的置信度低于该阈值,则认为识别失败。
2、Train方法
Train方法用于训练人脸识别模型,它将使用训练集图像和标签来训练人脸识别模型。其声明为:
public void Train(
Mat[] images,
int[] labels
)
参数说明:
- images:训练集图像,Mat数组,必须是灰度图像。
- labels:images数组中每张图像对应的标签数组,标签的数量必须等于训练图像的数量,且标签必须是连续的整数值。
3、predict方法
predict方法用于预测输入图像中的人脸是否匹配已训练的数据。
public FaceRecognizer. PredictionResult Predict(
IInputArray image
)
参数说明:
- Image:待识别的人脸图像。
返回值:
返回一个PredictionResult结构对象。PredictionResult结构的两个重要成员:
- Label:一个整数类型的成员变量,表示预测结果的标签,即输入图像在已知的训练数据中匹配的人脸标签。
- Distance:一个双精度浮点数类型的成员变量,表示输入图像与匹配的训练数据之间的距离值。通常情况下,距离值越小,表示输入图像与训练数据之间的相似度越高,预测结果的准确度也就越高。
注意:当调用predict方法出现预测失败时(例如,输入图像与训练数据中的所有图像都不匹配,或者训练数据中的图像数量过少,无法准确预测。),predict方法返回的PredictionResult对象,其中Label的值为-1,Distance的值为Double.MaxValue。
【代码位置:frmChapter10】Button5_Click
//人脸识别:LBPHFaceRecognizer
private void Button5_Click(object sender, EventArgs e)
{
//人脸训练数据
List<Mat> lstSrcM = new List<Mat>();
//标签序号
List<int> lstLbl = new List<int>();
//标签名称
List<string> lstLblName = new List<string>();
System.IO.DirectoryInfo mainDi = new System.IO.DirectoryInfo("C:\\learnEmgucv\\mingxing");
int index = 0;
//这里把不同的明星照片放到了mingxing目录中不同的子目录下
foreach (System.IO.DirectoryInfo di in mainDi.GetDirectories())
{
//从子目录中取出图像
foreach (System.IO.FileInfo fi in di.GetFiles())
{
//确保标签序号、标签名称、图像要一一对应
lstLbl.Add(index);
lstLblName.Add(di.Name);
Mat m = new Mat(fi.FullName, ImreadModes.Grayscale);
lstSrcM.Add(m);
}
index += 1;
}
//构造函数
LBPHFaceRecognizer recognizer = new LBPHFaceRecognizer(1, 8, 8, 8, 200);
//训练人脸识别模型
recognizer.Train(lstSrcM.ToArray(), lstLbl.ToArray());
//用来识别的图像,必须是灰度(单通道)图像
Mat mTest1 = new Mat("C:\\learnEmgucv\\ldh1.jpg", ImreadModes.Grayscale);
Emgu.CV.Face.FaceRecognizer.PredictionResult pr1;
//人脸进行匹配
pr1 = recognizer.Predict(mTest1);
int pos1 = lstLbl.IndexOf(pr1.Label);
string outname1 = lstLblName[pos1];
Console.WriteLine(outname1 + " 匹配度 " + pr1.Distance);
Mat mTest2 = new Mat("C:\\learnEmgucv\\ldh3.jpg", ImreadModes.Grayscale);
Emgu.CV.Face.FaceRecognizer.PredictionResult pr2;
pr2 = recognizer.Predict(mTest2);
int pos2 = lstLbl.IndexOf(pr2.Label);
string outname2 = lstLblName[pos2];
Console.WriteLine(outname2 + " 匹配度 " + pr2.Distance);
Mat mTest3 = new Mat("C:\\learnEmgucv\\fbb2.jpg", ImreadModes.Grayscale);
Emgu.CV.Face.FaceRecognizer.PredictionResult pr3;
pr3 = recognizer.Predict(mTest3);
int pos3 = lstLbl.IndexOf(pr3.Label);
string outname3 = lstLblName[pos3];
Console.WriteLine(outname3 + " 匹配度 " + pr3.Distance);
}
以上代码对2个明星的3张照片进行了识别,从输出结果来看,不是很理想。
【代码位置:frmChapter10】Button6_Click
//人脸识别:LBPHFaceRecognizer
//使用级联分类器提取人脸后进行识别
private void Button6_Click(object sender, EventArgs e)
{
CascadeClassifier face = new CascadeClassifier("C:\\learnEmgucv\\haarcascade\\haarcascade_frontalface_alt2.xml");
//人脸训练数据
List<Mat> lstSrcM = new List<Mat>();
//标签序号
List<int> lstLbl = new List<int>();
//标签名称
List<string> lstLblName = new List<string>();
System.IO.DirectoryInfo mainDi = new System.IO.DirectoryInfo("C:\\learnEmgucv\\mingxing");
int index = 0;
foreach (System.IO.DirectoryInfo di in mainDi.GetDirectories())
{
foreach (System.IO.FileInfo fi in di.GetFiles())
{
Mat m = new Mat(fi.FullName, ImreadModes.Grayscale);
//提取人脸区域
Rectangle[] rects = face.DetectMultiScale(m);
//因为样本库中的样本只有1个人脸
if( rects.Length > 0 )
{
//提取到的人脸区域,只需要考虑1个人脸的情况
Mat mface = new Mat(m, rects[0]);
CvInvoke.Resize(mface, mface, new Size(200, 200));
lstLbl.Add(index);
lstLblName.Add(di.Name + "-" + fi.Name);
lstSrcM.Add(mface);
index += 1;
}
}
}
LBPHFaceRecognizer recognizer = new LBPHFaceRecognizer(1, 8, 8, 8, 200);
recognizer.Train(lstSrcM.ToArray(), lstLbl.ToArray());
//需要检测的样本
Mat mTest1 = new Mat("C:\\learnEmgucv\\ldh1.jpg", ImreadModes.Grayscale);
Rectangle[] testRects1 = face.DetectMultiScale(mTest1);
if (testRects1.Length > 0)
{
Mat mtestface1 = new Mat(mTest1, testRects1[0]);
CvInvoke.Resize(mtestface1, mtestface1, new Size(200, 200));
FaceRecognizer.PredictionResult pr1 = recognizer.Predict(mtestface1);
int pos1 = lstLbl.IndexOf(pr1.Label);
string outname1 = lstLblName[pos1];
Console.WriteLine(outname1 + " 匹配度:" + pr1.Distance);
}
Mat mTest2 = new Mat("C:\\learnEmgucv\\ldh3.jpg", ImreadModes.Grayscale);
Rectangle[] testRects2 = face.DetectMultiScale(mTest2);
if (testRects2.Length > 0)
{
Mat mtestface2 = new Mat(mTest2, testRects2[0]);
CvInvoke.Resize(mtestface2, mtestface2, new Size(200, 200));
FaceRecognizer.PredictionResult pr2 = recognizer.Predict(mtestface2);
int pos2 = lstLbl.IndexOf(pr2.Label);
string outname2 = lstLblName[pos2];
Console.WriteLine(outname2 + " 匹配度:" + pr2.Distance);
}
Mat mTest3 = new Mat("C:\\learnEmgucv\\fbb2.jpg", ImreadModes.Grayscale);
Rectangle[] testRects3 = face.DetectMultiScale(mTest3);
if (testRects3.Length > 0)
{
Mat mtestface3 = new Mat(mTest3, testRects3[0]);
CvInvoke.Resize(mtestface3, mtestface3, new Size(200, 200));
FaceRecognizer.PredictionResult pr3 = recognizer.Predict(mtestface3);
int pos3 = lstLbl.IndexOf(pr3.Label);
string outname3 = lstLblName[pos3];
Console.WriteLine(outname3 + " 匹配度:" + pr3.Distance);
}
}
以上代码同样对2个明星的3张照片进行了识别,从输出结果来看,提取脸部后进行识别效果比较好。
10.2.2 BasicFaceRecognizer
BasicFaceRecognizer类是EmguCV中用于人脸识别(Face Recognition)的基础类之一,它提供了一些基本的人脸识别功能。与LBPHFaceRecognizer类不同的是,BasicFaceRecognizer类使用的是Eigenfaces(特征脸)或Fisherfaces(Fisher特征脸)算法进行人脸识别。
BasicFaceRecognizer类的识别准确度较低,因此在使用该类进行人脸识别时,需要保证训练数据的质量和数量,以提高识别准确率。如果需要更高的识别准确度,可以考虑使用LBPHFaceRecognizer类或其他更高级的人脸识别算法。
10.2.2.1 EigenFaceRecgnizer类
EigenFaceRecognizer类基于特征向量的人脸识别。它使用主成分分析(PCA)来提取训练集中的特征向量,并将其用于人脸识别。EigenFaceRecognizer类继承自BasicFaceRecognizer类。
关于EigenFaceRecognizer类的使用,请参看10.2.1节【 LBPHFaceRecgnizer类】。
【代码位置:frmChapter10】Button7_Click
//人脸识别:EigenFaceRecognizer
//使用级联分类器提取人脸后进行识别
private void Button7_Click(object sender, EventArgs e)
{
……
EigenFaceRecognizer recognizer = new EigenFaceRecognizer();
recognizer.Train(lstSrcM.ToArray(), lstLbl.ToArray());
……
}
10.2.2.2 FisherFaceRecognizer
FisherFaceRecognizer类使用Fisherfaces(Fisher特征脸)算法进行人脸识别,这是一种基于统计学习理论的高级算法,可以在一定程度上提高识别准确率。
关于EigenFaceRecognizer类的使用,请参看10.2.1节【 LBPHFaceRecgnizer类】。
【代码位置:frmChapter10】Button8_Click
//人脸识别:FisherFaceRecognizer
//使用级联分类器提取人脸后进行识别
private void Button8_Click(object sender, EventArgs e)
{
……
FisherFaceRecognizer recognizer = new FisherFaceRecognizer();
recognizer.Train(lstSrcM.ToArray(), lstLbl.ToArray());
……
}