123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- /*
- * Copyright (c) 2011. Philipp Wagner <bytefish[at]gmx[dot]de>.
- * Released to public domain under terms of the BSD Simplified license.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the organization nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * See <http://www.opensource.org/licenses/bsd-license>
- */
- #include "opencv2/core.hpp"
- #include "opencv2/face.hpp"
- #include "opencv2/highgui.hpp"
- #include <iostream>
- #include <fstream>
- #include <sstream>
- using namespace cv;
- using namespace cv::face;
- 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(Error::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[]) {
- // Check for valid command line arguments, print usage
- // if no arguments were given.
- if (argc != 2) {
- cout << "usage: " << argv[0] << " <csv.ext>" << endl;
- exit(1);
- }
- // Get the path to your CSV.
- string fn_csv = string(argv[1]);
- // 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 (const 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(Error::StsError, error_message);
- }
- // 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::LBPHFaceRecognizer 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::face::LBPHFaceRecognizer::create(2, 16);
- //
- // And if you want a threshold (e.g. 123.0) call it with its default values:
- //
- // cv::face::LBPHFaceRecognizer::create(1,8,8,8,123.0)
- //
- Ptr<LBPHFaceRecognizer> model = LBPHFaceRecognizer::create();
- 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;
- // First we'll use it to set the threshold of the LBPHFaceRecognizer
- // to 0.0 without retraining the model. This can be useful if
- // you are evaluating the model:
- //
- model->setThreshold(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->getRadius(),
- model->getNeighbors(),
- model->getGridX(),
- model->getGridY(),
- model->getThreshold());
- cout << model_info << endl;
- // We could get the histograms for example:
- vector<Mat> histograms = model->getHistograms();
- // But should I really visualize it? Probably the length is interesting:
- cout << "Size of the histograms: " << histograms[0].total() << endl;
- return 0;
- }
|