Renesas GR-PEACH OpenCV Development / gr-peach-opencv-project-sd-card_update

Fork of gr-peach-opencv-project-sd-card by the do

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers eigen_faces.cpp Source File

eigen_faces.cpp

00001 /*
00002  * Copyright (c) 2011,2012. Philipp Wagner <bytefish[at]gmx[dot]de>.
00003  * Released to public domain under terms of the BSD Simplified license.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *   * Redistributions of source code must retain the above copyright
00008  *     notice, this list of conditions and the following disclaimer.
00009  *   * Redistributions in binary form must reproduce the above copyright
00010  *     notice, this list of conditions and the following disclaimer in the
00011  *     documentation and/or other materials provided with the distribution.
00012  *   * Neither the name of the organization nor the names of its contributors
00013  *     may be used to endorse or promote products derived from this software
00014  *     without specific prior written permission.
00015  *
00016  *   See <http://www.opensource.org/licenses/bsd-license>
00017  */
00018 #include "precomp.hpp"
00019 #include "face_basic.hpp"
00020 #include <set>
00021 #include <limits>
00022 #include <iostream>
00023 
00024 namespace cv
00025 {
00026 namespace face
00027 {
00028 
00029 // Turk, M., and Pentland, A. "Eigenfaces for recognition.". Journal of
00030 // Cognitive Neuroscience 3 (1991), 71–86.
00031 class Eigenfaces : public BasicFaceRecognizerImpl
00032 {
00033 
00034 public:
00035     // Initializes an empty Eigenfaces model.
00036     Eigenfaces(int num_components = 0, double threshold = DBL_MAX)
00037         : BasicFaceRecognizerImpl(num_components, threshold)
00038     {}
00039 
00040     // Computes an Eigenfaces model with images in src and corresponding labels
00041     // in labels.
00042     void train(InputArrayOfArrays src, InputArray labels);
00043 
00044     // Send all predict results to caller side for custom result handling
00045     void predict(InputArray src, Ptr<PredictCollector> collector) const;
00046 };
00047 
00048 //------------------------------------------------------------------------------
00049 // Eigenfaces
00050 //------------------------------------------------------------------------------
00051 void Eigenfaces::train(InputArrayOfArrays _src, InputArray _local_labels) {
00052     if(_src.total() == 0) {
00053         String error_message = format("Empty training data was given. You'll need more than one sample to learn a model.");
00054         CV_Error(Error::StsBadArg, error_message);
00055     } else if(_local_labels.getMat().type() != CV_32SC1) {
00056         String error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _local_labels.type());
00057         CV_Error(Error::StsBadArg, error_message);
00058     }
00059     // make sure data has correct size
00060     if(_src.total() > 1) {
00061         for(int i = 1; i < static_cast<int>(_src.total()); i++) {
00062             if(_src.getMat(i-1).total() != _src.getMat(i).total()) {
00063                 String error_message = format("In the Eigenfaces method all input samples (training images) must be of equal size! Expected %d pixels, but was %d pixels.", _src.getMat(i-1).total(), _src.getMat(i).total());
00064                 CV_Error(Error::StsUnsupportedFormat, error_message);
00065             }
00066         }
00067     }
00068     // get labels
00069     Mat labels = _local_labels.getMat();
00070     // observations in row
00071     Mat data = asRowMatrix(_src, CV_64FC1);
00072 
00073     // number of samples
00074    int n = data.rows;
00075     // assert there are as much samples as labels
00076     if(static_cast<int>(labels.total()) != n) {
00077         String error_message = format("The number of samples (src) must equal the number of labels (labels)! len(src)=%d, len(labels)=%d.", n, labels.total());
00078         CV_Error(Error::StsBadArg, error_message);
00079     }
00080     // clear existing model data
00081     _labels.release();
00082     _projections.clear();
00083     // clip number of components to be valid
00084     if((_num_components <= 0) || (_num_components > n))
00085         _num_components = n;
00086 
00087     // perform the PCA
00088     PCA pca(data, Mat(), PCA::DATA_AS_ROW, _num_components);
00089     // copy the PCA results
00090     _mean = pca.mean.reshape(1,1); // store the mean vector
00091     _eigenvalues = pca.eigenvalues.clone(); // eigenvalues by row
00092     transpose(pca.eigenvectors, _eigenvectors); // eigenvectors by column
00093     // store labels for prediction
00094     _labels = labels.clone();
00095     // save projections
00096     for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) {
00097         Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx));
00098         _projections.push_back(p);
00099     }
00100 }
00101 
00102 void Eigenfaces::predict(InputArray _src, Ptr<PredictCollector> collector) const {
00103     // get data
00104     Mat src = _src.getMat();
00105     // make sure the user is passing correct data
00106     if(_projections.empty()) {
00107         // throw error if no data (or simply return -1?)
00108         String error_message = "This Eigenfaces model is not computed yet. Did you call Eigenfaces::train?";
00109         CV_Error(Error::StsError, error_message);
00110     } else if(_eigenvectors.rows != static_cast<int>(src.total())) {
00111         // check data alignment just for clearer exception messages
00112         String error_message = format("Wrong input image size. Reason: Training and Test images must be of equal size! Expected an image with %d elements, but got %d.", _eigenvectors.rows, src.total());
00113         CV_Error(Error::StsBadArg, error_message);
00114     }
00115     // project into PCA subspace
00116     Mat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1, 1));
00117     collector->init(_projections.size());
00118     for (size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) {
00119         double dist = norm(_projections[sampleIdx], q, NORM_L2);
00120         int label = _labels.at<int>((int)sampleIdx);
00121         if (!collector->collect(label, dist))return;
00122     }
00123 }
00124 
00125 Ptr<BasicFaceRecognizer> createEigenFaceRecognizer (int num_components, double threshold)
00126 {
00127     return makePtr<Eigenfaces>(num_components, threshold);
00128 }
00129 
00130 }
00131 }
00132