在上一篇文章 【Opencv综合应用】自制训练集的人脸识别2——制作csv文件中我们已经生成了csv文件,现在将使用VS2017来把csv文件制作成xml的训练集文件了
说明
本文参考自https://www.cnblogs.com/fpzs/p/10550305.html
由于参考博客中的Opencv版本很老了,并且其中有漏写的地方,我的版本为Opencv4.1.0,导致运行代码后有多处报错,我对其中错误进行修改后汇总如下:
原代码中模型训练部分createEngenFaceRecognize(); createFisherFaceRecognizer(); createLBPHFaceRecognizer();
需要更改为EigenFaceRecognize::create(); FisherFaceRecognizer::create(); LBPHFaceRecognizer::create();
model2对应的训练缺少了,需要在模型训练部分增加
Ptr<FaceRecognizer> model2 = LBPHFaceRecognizer::create();
model2->train(images, labels);
model2->save("MyFaceLBPHModel.xml");
包含头文件#include< face/face.hpp >
命名空间using namespace cv::face;
一,环境准备
我的环境为win10+opencv4.1.0+VS2017。因为人脸模型训练模块在opencv-contrib模块中,而官方的OpenCV安装包中是不带opencv-contrib的,所以需自行下载opencv-contrib-4.1.0模块,然后将opencv4.1.0和opencv-contrib-4.1.0一起进行重新编译。需要注意opencv-contrib的版本必须要和opencv的版本相一致,不然程序无法运行。
二,主要步骤
创建一个自己的新VS项目,由于上一篇中我们写进att.txt的地址是相对地址,故需要将上一篇中已经生成的att.txt文件放到新建项目文件夹中可执行文件目录下(就是与文件后缀带cpp的同一目录),然后把ORL人脸库的att文件夹也放到同一目录下(这里很重要,因为写入的是相对地址,不连着文件夹一起移动是读不到图片的,当然要是一开始写入att.txt中的是绝对地址那就不用移动ORL人脸库文件了)
1.创建了一个特征脸模型用于人脸识别
2.通过CSV文件att.txt读取的图像和标签训练它
3.创建一个PCA人脸分类器,T这里是一个完整的PCA变换
4.调用其中的成员函数train()来完成分类器的训练
通过CSV文件att.txt去读图像和标签,主要使用stringstream和getline方法
/*****************
函数:static void read_csv(const string& filename,vector<Mat>images, vector<int> labels,int CountMax,int CountMin, char separator=';')
功能:读取csv文件的图像路径和标签。主要使用stringstream和getline()
参数说明:
filename--要读取的csv文件
images----读取的图片(向量)
labels----读取的图片对应标签 (向量)
CountMax,int CountMin--读取的每一类别的图片下标的最大值和最小值(默认每个类别共10张照片)
separator-分隔符,起控制读取的作用。可自定义为逗号空格等,(此程序中)默认为分号
返回值:空
*****************/
static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';')
{
std::ifstream file(filename.c_str(), ifstream::in);//c_str()函数可用可不用,无需返回一个标准C类型的字符串
if (!file)
{
string error_message = "No valid input file was given, please check the given filename.";
//CV_Error(CV_StsBadArg, error_message);这里注释掉是由于会报错
}
string line, path, classlabel;
while (getline(file, line)) //从文本文件中读取一行字符,未指定限定符默认限定符为“/n”
{
stringstream liness(line);
getline(liness, path, separator); //这里采用stringstream主要作用是做字符串的分割
getline(liness, classlabel); //读入图片文件路径以分好作为限定符
if (!path.empty() && !classlabel.empty())
{
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));//如果读取成功,则将图片和对应标签压入对应容器中
}
}
}
我们在代码里面用到了Facerecognizer类,opencv中所有的人脸识别模型都是来源于这个类。以下是opencv-contrib库中带着的三个人脸识别算法:EigenFace,FisherFace &