【opencv人脸识别4】训练人脸模型

        本节讲如何训练人脸模型,所用平台为opencv3.4.0+VS2017+win10。因为人脸模型训练模块在opencv_contrib模块中,而在opencv2.x版本中是有这个模块的,但考虑到此模块的不稳定性,opencv3.x版本将此模块去掉了,所以若需要应用opencv_contrib模块,需自行下载opencv_contrib_3.4.0模块,然后用cmake软件将opencv3.4和opencv_contrib_3.4.0一起进行重新编译。

        此处需注意,opencv_contrib的版本要和opencv的版本相一致,不然程序无法运行。

一.说明

    首先说明:opencv3.x较opencv2.x在FaceRecogna的使用区别:

  • 首先需要配置contrib模块,这在很多博客中有介绍
  • OpenCV3.4.0的人脸识别API相较于之前opencv2.x的版本有些变动
  • 原3.x以前的是createEngenFaceRecognize()
  • 现更改为EigenFaceRecognize::create()
  • 其他几个创建函数也做了如上改变。
  • 包含头文件#include< face/face.hpp >
  • 命名空间using namespace cv::face;

    opencv中有三种方法可以使用:

     EigenFaceRecognizer::create()、FisherFaceRecognizer::create()LBPHFaceRecognizer::create()

    我选择的是EigenFaceRecognizer::create() ,其他的两种也一样,只需要改一下定义即可。

Ptr<face::FaceRecognizer> model = EigenFaceRecognizer::create(20);//  创建特征脸模型 20张主成分脸   

    要进行人脸识别,需要一个人脸识别的模型,本实验采用PCA模型,取前20个主成分脸。

    训练人脸模型的流程图如下:

                                  

人脸模型训练的步骤如下:

    1.前期准备工作,将所有的人脸样本和类别标签生成一个.csv文件。

            生成csv文件方法:http://blog.csdn.net/u012679707/article/details/79519143   

        

        本实验所采用的实验数据来自ORL人脸库,人脸图为灰度图,大小为92*112。

                

    2.训练时可直接读取csv文件,实现样本和类别标签的获取。

            读取csv文档方法: http://blog.csdn.net/u012679707/article/details/78711365 

    3.创建特征脸模型,选择20个主成分   (faceRecognizer 为cv2中的contrib模块)

Ptr<FaceRecognizer> model=createEigenFaceRecognizer(20); // 创建特征脸模型 20张主成分脸  

    4.通过样本和类别标签进行训练,最终得到训练好的主成分脸模型。

model->train(images,labels); //训练人脸模型,通过images和labels来训练人脸模型  

    5.将模型保存为.xml文件

model->save("MyFacePcaModel.xml"); //将训练模型保存到MyFacePcaModel.xml  

    注意:contrib模块中的人脸识别模型有三种,PCA、fisher、LBP。本系统选择的是主成分脸模型(PCA)


整个程序:
//face_recog_from_video.cpp 定义控制台应用程序的入口点。

// train_PCA_model.cpp  
//用于训练人脸识别所需的pCA模型  
#include "stdafx.h"
#include"opencv2/opencv.hpp"
#include"opencv2/core.hpp"
#include"opencv2/imgproc.hpp"
#include"opencv2/highgui.hpp"
#include"opencv2/face.hpp"  // 包含FaceRecognizer
#include<iostream>

using namespace std;
using namespace cv;
using namespace cv::face;


static  void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, int max, int min, char separator);
int CountMax = 9, CountMin = 0;


int  main(int argc, char *argv[])
{
	string csvFile = ".\\data\\at.txt";
	vector<Mat> images;
	vector<int> labels;


	// 读取csv文件  
	try
	{
		read_csv(csvFile, images, labels, CountMax, CountMin, ';'); //读取csvFile中所有的img和label  
	}
	catch (cv::Exception& e) // 异常检查  
	{                  // cerr:输出到标准错误的ostream对象,常用于程序错误信息  
		cerr << "Error opening file\" " << csvFile << "\".reason: " << e.msg << endl; //异常 发生的原因  
		exit(-1);
	}


	// 若未读取到足够图片,也退出  
	if (images.size() <= 1)
	{
		string errMsg = "THis demo needs at least 2 images to work.please add images!";
		CV_Error(CV_StsError, errMsg);

	}
	cout << "train1.读取ok" << endl;

	// 训练数据,并将训练好的人脸模型保存到.xml中  
	// Ptr<>为模板类,定义model为指向FaceRecognizer类的指针。model为指针!    
//	Ptr<EigenFaceRecognizer> model= EigenFaceRecognizer::create();// createEigenFaceRecognizer(20); // 创建特征脸模型 20张主成分脸   EigenFaceRecognizer::create();//  
	Ptr<EigenFaceRecognizer> model = EigenFaceRecognizer::create();
	model->train(images, labels); //训练  
	model->save("MyFacePcaModel.xml"); //将训练模型保存到MyFacePcaModel.xml  

	cout << "train2.创建脸模型ok" << endl;
	return 0;

}


/*
函数: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-分隔符,起控制读取的作用。可自定义为逗号空格等,(此程序中)默认为分号
返回值:空
*/
/*
备注:(函数内部涉及到的部分类和方法说明)
1. stringstream:字符串流。
功能:将内存中的对象与流绑定。

2. getline():
函数原型:istream &getline( ifstream &input,string &out,char dielm)
参数说明:Input--输入文件
out----输出字符串
dielm--读取到该字符停止(起到控制作用),默认是换行符‘\n’
功能: 读取文件Input中的字符串到out中。
返回值:返回Input,若是文件末尾会返回文件尾部标识eof

3. ifstream: 从硬盘打开文件(读取),从磁盘输入文件,读到内存中
ofstream: 从内存打开文件(读取),从内存输入文件,读到磁盘中)
*/
static  void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, int max, int min, char separator)
{
	std::ifstream  file(filename.c_str(), ifstream::in); // 以in模式(读取文件模式)打开文件 ,实际是将filename文件关联给 流file 

	if (!file)
	{
		string error_message = "No valid input file was given,please check the given filename";
		CV_Error(CV_StsBadArg, error_message);

	}
	int ii = 0;

	/**********************读取文件.txt内容****************************/
	string line, path, label;
	// [1]读取file文件中的一行字符串给 line  
	while (getline(file, line, '\n'))  // 控制:直到读到file文件末尾(eof标识),才跳出while  
	{
		// [2]将line整行字符串读取到lines(流)中  
		stringstream lines(line); //区别->lines是流,读取字符时,指针会随流而动;而line是string,固定的,下文中的读取每次都是从line头开始  
								  // [3]读取文件中的路径和标签  
		getline(lines, path, separator); //此时光标已走到path之后的位置(即;分号处)  
		getline(lines, label);
		// [4]将图片和标签加入imgs 和 labels  
		if ((path.empty() == 0) && (label.empty() == 0))
		{
			if (ii % 10 <= max && ii % 10 >= min)  //默认每个类别共10张照片  
			{
				Mat img = imread(path, 0);  //第二个参数为0 !!!  
											//Mat img = imread(ImageFileAddress, CV_LOAD_IMAGE_GRAYSCALE),CV_LOAD_IMAGE_GRAYSCALE值为 0,指灰图(原本为“CV_LOAD_IMAGE_UNCHANGED”)  
				if (img.data != 0)
				{
					images.push_back(img); // 将图片 添加到images中  
					labels.push_back(atoi(label.c_str()));
				}
			}
			if (ii<9) ii++;
			else ii = 0;

		}
	}
}

    注意:程序中数据读取,主要是先生成csv文件,再读取csv文件,具体可见:

        1.利用cmd生成csv文件的方法

        2.人脸识别之读取csv文件

运行结果:

    最终生成的MyFacePcaModel.xml文件内容如下图所示,其中

<num_components>20</num_components>   20是主特征脸的个数 
<rows>1</rows>  
<cols>10304</cols>       1*10304 这表示每个特征脸的大小,一行表示一张脸的数据,维度为10304(92*112)  

    MyFacePcaModel.xml如下:

                      

这样,我们就得到了人脸模型文件“MyFacePcaModel.xml”,可用于后边的预测和识别。

 -------------------------------------------         END      -------------------------------------

猜你喜欢

转载自blog.csdn.net/u012679707/article/details/80397012