训练模型
*开发环境为visual studio2010
*使用的数据集是face.txt
*用到Facerecognizer类。opencv中所有的人脸识别模型都是来源于这个类。
一:主要步骤
1.创建了一个特征脸模型用于人脸识别 2.通过CSV文件face.txt读取的图像和标签训练它
3.创建一个PCA人脸分类器,T这里是一个完整的PCA变换
4.调用其中的成员函数train()来完成分类器的训练
二:代码
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/core/core.hpp> 3 #include "opencv2/face/facerec.hpp" 4 #include "opencv2/face.hpp" 5 #include "opencv2/core.hpp" 6 #include "opencv2/highgui.hpp" 7 #include "opencv2/imgproc.hpp" 8 #include <iostream> 9 #include <fstream> 10 #include <sstream> 11 #include <math.h> 12 using namespace cv; 13 using namespace cv::face; 14 using namespace std; 15 16 static Mat norm_0_255(InputArray _src) 17 { 18 Mat src = _src.getMat(); 19 // 创建和返回一个归一化后的图像矩阵: 20 Mat dst; 21 switch (src.channels()) 22 { 23 case 1: 24 cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1); 25 break; 26 case 3: 27 cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3); 28 break; 29 default: 30 src.copyTo(dst); 31 break; 32 } 33 return dst; 34 } 35 36 //使用CSV文件去读图像和标签,主要使用stringstream和getline方法 37 static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';') 38 { 39 std::ifstream file(filename.c_str(), ifstream::in);//c_str()函数可用可不用,无需返回一个标准C类型的字符串 40 if(!file) 41 { 42 string error_message = "No valid input file was given, please check the given filename."; 43 CV_Error(CV_StsBadArg, error_message); 44 } 45 string line, path, classlabel; 46 while(getline(file,line)) //从文本文件中读取一行字符,未指定限定符默认限定符为“/n”� 47 { 48 stringstream liness(line); 49 getline(liness, path, separator); //这里采用stringstream主要作用是做字符串的分割 50 getline(liness,classlabel); //读入图片文件路径以分好作为限定符 51 if (!path.empty() && !classlabel.empty()) 52 { 53 images.push_back(imread(path,0)); 54 labels.push_back(atoi(classlabel.c_str()));///如果读取成功,则将图片和对应标签压入对应容器中 55 56 } 57 58 } 59 } 60 61 int main() 62 { 63 //读取你的CSV文件路径. 64 string fn_csv = "face.txt"; 65 66 // 2个容器来存放图像数据和对应的标签 67 vector<Mat> images; 68 vector<int> labels; 69 70 // 读取数据. 如果文件不合法就会出错 71 72 try 73 { 74 read_csv(fn_csv, images, labels); 75 } 76 catch (cv::Exception& e) 77 { 78 cerr << "Error opening file "" << fn_csv << "".Reason: " << e.msg << endl; 79 exit(1); 80 } 81 // 如果没有读取到足够图片,也退出. 82 if(images.size() <= 1) 83 { 84 string error_message = " Please add more images to your data set!"; 85 CV_Error(CV_StsError, error_message); 86 } 87 88 for (int i = 0; i < images.size(); i++) 89 { 90 if(images[i].size() != Size(92, 112)) 91 { 92 cout << i << endl; 93 cout << images[i].size() << endl; 94 } 95 } 96 // 下面的几行代码仅仅是从你的数据集中移除最后一张图片,作为测试图片 97 //[gm:自然这里需要根据自己的需要修改,他这里简化了很多问题] 98 Mat testSample = images[images.size() - 1]; 99 int testLabel = labels[labels.size() - 1]; 100 images.pop_back(); //删除最后一张照片,此照片作为测试图片 101 labels.pop_back(); //删除最有一张照片的labels 102 103 // 创建了一个特征脸模型用于人脸识别, 104 // 通过CSV文件读取的图像和标签训练它。 105 // T这里是一个完整的PCA变换 106 //创建一个PCA人脸分类器, 107 //调用其中的成员函数train()来完成分类器的训练 108 Ptr<BasicFaceRecognizer> model0 = createEigenFaceRecognizer(); 109 model0->train(images,labels); 110 111 //save the model to .xml 112 model0->save("MyEigenFaces.xml"); 113 114 Ptr<BasicFaceRecognizer> model1 = createFisherFaceRecognizer(); 115 model1->train(images,labels); 116 model1->save("MyFaceModel.xml"); 117 118 // 还有一种调用方式,可以获取结果同时得到阈值: 119 // int predictedLabel = -1; 120 // double confidence = 0.0; 121 // model->predict(testSample, predictedLabel, confidence); 122 123 int predictedLabel0 = model0->predict(testSample); 124 int predictedLabel1 = model1->predict(testSample); 125 int predictedLabel2 = model2->predict(testSample); 126 127 string result_message0 = format("Predicted class = %d / Actual class = %d.",predictedLabel0, testLabel); 128 string result_message1 = format("Predicted class = %d / Actual class = %d.",predictedLabel1, testLabel); 129 string result_message2 = format("Predicted class = %d / Actual class = %d.",predictedLabel2, testLabel); 130 131 cout << result_message0 << endl; 132 cout << result_message1 << endl; 133 cout << result_message2 << endl; 134 135 waitKey(0); 136 return 0; 137 }
三:训练结果
生成了MyFaceModel.xml文件,可以直接使用进行人脸识别