目录
- 1、Creating the CSV File
- 2、读取CSV文件函数
- 3、开始训练模型
- 4、程序
1、Creating the CSV File
照片需要在程序中读取它,我决定使用CSV文件读取它。一个CSV文件包含文件名,紧跟一个标签。
/path/to/image.ext;0
假设/path/to/image.ext是图像,就像你在windows下的c:/faces/person0/image0.jpg。最后我们给它一个标签0。这个标签类似代表这个照片的名字,所以同一张的照片的标签都一样。
打开DOS命令即打开命令控制台,进入相对路径下去,然后进入储存照片的路径下去输入f:\opencv_example\pic>dir /b/s *.jpg >at.txt
即可生成at.txt文件
2、读取CSV文件函数
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);//这里采用stringstream主要作用是做字符串的分割getline(liness, path, separator);//读入图片文件路径以分好作为限定符getline(liness, classlabel);//读入图片标签,默认限定符if (!path.empty() && !classlabel.empty())//如果读取成功,则将图片和对应标签压入对应容器中 {images.push_back(imread(path, 0));labels.push_back(atoi(classlabel.c_str()));}}
}
3、开始训练模型
(1)创建一个图像容器和标签容器(createEigenFaceRecognizer()函数来创建分类器时是可以人为指定训练结果的维数以及判别阈值,这里我们采用系统默认的参数)来存储训练图像以及对应人脸标签,然后调用void read_csv()填充这两个容器;
(2)然后创建一个PCA人脸分类器,暂时命名为model吧,创建完成后,调用其中的成员函数train()(train()函数的执行时间与训练样本图片数目有关)来完成分类器的训练。
(3)训练得到的分类器model用save()函数保存成XML文件存储下来,下次用的时候直接用laod()加载就行,
#include<iostream>
#include <fstream>
#include <sstream>
#include <opencv2\opencv.hpp>
#include <opencv2\face.hpp>
#include <windows.h>
#include <direct.h> using namespace cv;
using namespace std;
using namespace face;CascadeClassifier face_cascades;
//读取CSV文件函数
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);//这里采用stringstream主要作用是做字符串的分割getline(liness, path, separator);//读入图片文件路径以分好作为限定符getline(liness, classlabel);//读入图片标签,默认限定符if (!path.empty() && !classlabel.empty())//如果读取成功,则将图片和对应标签压入对应容器中 {images.push_back(imread(path, 0));labels.push_back(atoi(classlabel.c_str()));}}
}int main()
{char buffer[MAX_PATH];_getcwd(buffer, MAX_PATH);printf("The buffer is: %s ", buffer);string fn_csv;fn_csv = buffer;fn_csv = fn_csv + "F:\\opencv_example\\pic\\at.txt";//string fn_csv = "./pic/at.txt";//读取你的CSV文件路径. 相对路径读取失败linuxvector<Mat> images;// 2个容器来存放图像数据和对应的标签vector<int> labels;read_csv(fn_csv, images, labels);//从csv文件中批量读取训练数据Ptr<FaceRecognizer> model = createEigenFaceRecognizer();model->train(images, labels);model->save("F:\\opencv_example\\pic\\MyFaceRecognizer.xml");//保存路径return 0;
}
4、程序
还可以输出一些与训练集相关的结构,比如训练集的均值特征脸、重构特征脸等
//获得特征值,特征向量,均值 平均脸
Mat eigenvalues = model->getEigenValues();
Mat eigenvectors = model->getEigenVectors();
Mat mean = model->getMean();
Mat meanFace = mean.reshape(1, height);
Mat dst;
dst = normal(meanFace, dst);
imshow(“Mean Face”, dst);
//特征脸
for (int i = 0; i < min(10, eigenvectors.cols); i++)
{Mat ev = eigenvectors.col(i).clone();Mat eigenFace = ev.reshape(1, height);Mat grayscale;grayscale = normal(eigenFace, grayscale);Mat colorface;applyColorMap(grayscale, colorface, COLORMAP_BONE);char* winTitle = new char[128];sprintf(winTitle, "eigenface_%d", i);imshow(winTitle, colorface);
}//重建人脸
for (int num = min(10, eigenvectors.cols); num < min(300, eigenvectors.cols); num += 15)
{Mat evs = Mat(eigenvectors, Range::all(), Range(0, num));Mat projection = LDA::subspaceProject(evs, mean, image[0].reshape(1, 1));Mat reconstruction = LDA::subspaceReconstruct(evs, mean, projection);Mat result = reconstruction.reshape(1, height);reconstruction = normal(result, reconstruction);char* winTitle = new char[128];sprintf(winTitle, "recon_face_%d", num);imshow(winTitle, reconstruction);
}