OpenCV学习(40) 人脸识别(4)
在人脸识别模式类中,还实现了一种基于LBP直方图的人脸识别方法。LBP图的原理参照:http://www.cnblogs.com/mikewolf2002/p/3438698.html 在代码中,我们只要使用 Ptr<FaceRecognizer> model = createLBPHFaceRecognizer(); 就创建了一个基于LBPH的人脸识别类,其它代码和前面两种人脸识别方法一样。 在train函数中,会计算每个样本的LBP图像,并求出该图像的二维直方图,把直方图保存在_histograms中,以便在predict函数调用这些直方图进行匹配。 for(size_t sampleIdx = 0; sampleIdx < src.size(); sampleIdx++) { // 计算LBP图 Mat lbp_image = elbp(src[sampleIdx], _radius, _neighbors); // 得到直方图 Mat p = spatial_histogram( lbp_image, /* lbp_image */ static_cast<int>(std::pow(2.0, static_cast<double>(_neighbors))), //可能的模式数 _grid_x, /* grid size x */ _grid_y, /* grid size y */ true); // 把直方图加到匹配模版中 _histograms.push_back(p); } 在预测函数中,会先求出输入图像的LBPH图,然后和保存的样本LBPH进行比较,距离最今即为匹配的人脸。 Mat lbp_image = elbp(src, _radius, _neighbors); Mat query = spatial_histogram( lbp_image, /* lbp_image */ static_cast<int>(std::pow(2.0, static_cast<double>(_neighbors))), /* number of possible patterns */ _grid_x, /* grid size x */ _grid_y, /* grid size y */ true /* normed histograms */); // 查找最近的匹配者 minDist = DBL_MAX; minClass = -1; for(size_t sampleIdx = 0; sampleIdx < _histograms.size(); sampleIdx++) { double dist = compareHist(_histograms[sampleIdx], query, CV_COMP_CHISQR); if((dist < minDist) && (dist < _threshold)) { minDist = dist; minClass = _labels.at<int>((int) sampleIdx); } } 代码: #include "opencv2/core/core.hpp"#include "opencv2/contrib/contrib.hpp"#include "opencv2/highgui/highgui.hpp"#include <iostream>#include <fstream>#include <sstream>using namespace cv;using namespace std;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, please check the given filename."; 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, const char *argv[]) {// Get the path to your CSV. string fn_csv = string("facerec_at_t.txt");// These vectors hold the images and corresponding labels. vector<Mat> images; vector<int> labels;// Read in the data. This can fail if no valid// input filename is given.try { read_csv(fn_csv, images, labels); } catch (cv::Exception& e) { cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;// nothing more we can do exit(1); }// Quit if there are not enough images for this demo.if(images.size() <= 1) { string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!"; CV_Error(CV_StsError, error_message); }// Get the height from the first image. We'll need this// later in code to reshape the images to their original// size:int height = images[0].rows;// The following lines simply get the last images from// your dataset and remove it from the vector. This is// done, so that the training data (which we learn the// cv::FaceRecognizer on) and the test data we test// the model with, do not overlap. Mat testSample = images[images.size() - 1];int testLabel = labels[labels.size() - 1]; images.pop_back(); labels.pop_back();// The following lines create an LBPH model for// face recognition and train it with the images and// labels read from the given CSV file.//// The LBPHFaceRecognizer uses Extended Local Binary Patterns// (it's probably configurable with other operators at a later// point), and has the following default values//// radius = 1// neighbors = 8// grid_x = 8// grid_y = 8//// So if you want a LBPH FaceRecognizer using a radius of// 2 and 16 neighbors, call the factory method with://// cv::createLBPHFaceRecognizer(2, 16);//// And if you want a threshold (e.g. 123.0) call it with its default values://// cv::createLBPHFaceRecognizer(1,8,8,8,123.0)// Ptr<FaceRecognizer> model = createLBPHFaceRecognizer(); model->train(images, labels);// The following line predicts the label of a given// test image:int predictedLabel = model->predict(testSample);//// To get the confidence of a prediction call the model with://// int predictedLabel = -1;// double confidence = 0.0;// model->predict(testSample, predictedLabel, confidence);// string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel); cout << result_message << endl;// Sometimes you'll need to get/set internal model data,// which isn't exposed by the public cv::FaceRecognizer.// Since each cv::FaceRecognizer is derived from a// cv::Algorithm, you can query the data.//// First we'll use it to set the threshold of the FaceRecognizer// to 0.0 without retraining the model. This can be useful if// you are evaluating the model:// model->set("threshold", 0.0);// Now the threshold of this model is set to 0.0. A prediction// now returns -1, as it's impossible to have a distance below// it predictedLabel = model->predict(testSample); cout << "Predicted class = " << predictedLabel << endl;// Show some informations about the model, as there's no cool// Model data to display as in Eigenfaces/Fisherfaces.// Due to efficiency reasons the LBP images are not stored// within the model: cout << "Model Information:" << endl; string model_info = format("\tLBPH(radius=%i, neighbors=%i, grid_x=%i, grid_y=%i, threshold=%.2f)", model->getInt("radius"), model->getInt("neighbors"), model->getInt("grid_x"), model->getInt("grid_y"), model->getDouble("threshold")); cout << model_info << endl;// We could get the histograms for example: vector<Mat> histograms = model->getMatVector("histograms");// But should I really visualize it? Probably the length is interesting: cout << "Size of the histograms: " << histograms[0].total() << endl;return 0; } 程序代码:工程FirstOpenCV35