从OpenCV2.4开始,加入新的类FaceRecognizer,可以用它方便的进行人脸识别实验。
目前支持的算法有
Eigenface特征脸 createEigenFaceRecognizer()
Fisherface createFisherFaceRecognizer()
Local Binary Patterns Histograms局部二值直方图 createLBPHFaceRecognizer()
这篇文章就特征脸方法进行了实验,代码是根据OpenCV2.4.3里面的samples/cpp文件的facerec_demo.cpp例程所改写的,人脸库用的是ORL人脸数据库,使用CSV文件来记录人脸库中图片所在的目录和标签。
算法描述:
令 表示一个随机特征,其中 .
- 计算均值向量
- 计算协方差矩阵 S
- 计算的特征值 和对应的特征向量
- 对特征值进行递减排序,特征向量和他的顺序一致。K个主成分也就是K和最大的特征值对应的特征向量。
x的K个主成分:
其中 .
PCA基的重构:
其中 .
然后特征脸通过下面的方式进行人脸识别:
1.把所有的训练数据投影大PCA子空间
2.把待识别的图像投影到PCA子空间
3.找到训练数据投影后的想来那个和待识别图像投影后的向量最近的那个。
源代码:
- #if 1
-
- #include <opencv2\contrib\contrib.hpp>
- #include <opencv2\core\core.hpp>
- #include <opencv2\highgui\highgui.hpp>
-
- #include <iostream>
- #include <fstream>
- #include <sstream>
-
- using namespace std;
- using namespace cv;
-
- static Mat norm_0_255(cv::InputArray _src)
- {
- Mat src = _src.getMat();
- Mat dst;
-
- switch(src.channels())
- {
- case 1:
- cv::normalize(_src, dst, 0, 255, cv::NORM_MINMAX, CV_8UC1);
- break;
- case 3:
- cv::normalize(_src, dst, 0, 255, cv::NORM_MINMAX, CV_8UC3);
- break;
- default:
- src.copyTo(dst);
- break;
- }
-
- return dst;
- }
-
- static void read_csv(const string &filename, vector<Mat> &images, vector<int> &labels, char separator = ';')
- {
- std::ifstream file(filename.c_str(), ifstream::in);
- if(!file)
- {
- string error_message = "No valid input file was given.";
- CV_Error(CV_StsBadArg, error_message);
- }
-
- string line, path, classlabel;
- while(getline(file, line))
- {
- stringstream liness(line);
- 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(int argc, char *argv[])
- {
- string output_folder;
- output_folder = string("D:\\ORL\\result");
-
-
- string fn_csv = string("D:\\ORL\\to\\at.txt");
-
-
- vector<Mat> images;
- vector<int> labels;
-
- try
- {
- read_csv(fn_csv, images, labels);
- }
- catch(cv::Exception &e)
- {
- cerr<<"Error opening file "<<fn_csv<<". Reason: "<<e.msg<<endl;
- exit(1);
- }
-
-
- if(images.size() <= 1)
- {
- string error_message = "This demo needs at least 2 images to work.";
- CV_Error(CV_StsError, error_message);
- }
-
-
- int height = images[0].rows;
-
-
- Mat testSample = images[images.size() - 1];
- cv::imshow("testSample", testSample);
- int testLabel = labels[labels.size() - 1];
-
- images.pop_back();
- labels.pop_back();
-
-
-
-
-
-
-
- cv::Ptr<cv::FaceRecognizer> model = cv::createEigenFaceRecognizer();
- model->train(images, labels);
-
-
-
-
- int predictedLabel = model->predict(testSample);
-
- string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
- cout<<result_message<<endl;
-
-
-
- Mat eigenvalues = model->getMat("eigenvalues");
-
- Mat W = model->getMat("eigenvectors");
-
-
- Mat mean = model->getMat("mean");
-
- imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)));
- cv::imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows)));
-
-
- for(int i=0; i <min(10, W.cols); i++)
- {
- string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
- cout<<msg<<endl;
-
- Mat ev = W.col(i).clone();
-
-
- Mat grayscale = norm_0_255(ev.reshape(1,height));
-
-
- Mat cgrayscale;
- cv::applyColorMap(grayscale, cgrayscale, COLORMAP_JET);
-
- imshow(format("eigenface_%d", i), cgrayscale);
- imwrite(format("%s/eigenface_%d.png", output_folder.c_str(), i), cgrayscale);
- }
-
-
- for(int num_components = 10; num_components < 390; num_components += 15)
- {
-
- Mat evs = Mat(W, Range::all(), Range(0, num_components));
-
- Mat projection = cv::subspaceProject(evs, mean, images[0].reshape(1,1));
-
- Mat reconstruction = cv::subspaceReconstruct(evs, mean, projection);
-
- reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
-
- imshow(format("eigenface_reconstruction_%d", num_components),reconstruction);
- imwrite(format("%s/eigenface_reconstruction_%d.png", output_folder.c_str(),num_components), reconstruction);
-
- }
-
- cv::waitKey(0);
- return 0;
- }
-
- #endif