Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project-sd-card by
fisher_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 00021 namespace cv { namespace face { 00022 00023 // Belhumeur, P. N., Hespanha, J., and Kriegman, D. "Eigenfaces vs. Fisher- 00024 // faces: Recognition using class specific linear projection.". IEEE 00025 // Transactions on Pattern Analysis and Machine Intelligence 19, 7 (1997), 00026 // 711–720. 00027 class Fisherfaces: public BasicFaceRecognizerImpl 00028 { 00029 public: 00030 // Initializes an empty Fisherfaces model. 00031 Fisherfaces(int num_components = 0, double threshold = DBL_MAX) 00032 : BasicFaceRecognizerImpl(num_components, threshold) 00033 { } 00034 00035 // Computes a Fisherfaces model with images in src and corresponding labels 00036 // in labels. 00037 void train(InputArrayOfArrays src, InputArray labels); 00038 00039 // Send all predict results to caller side for custom result handling 00040 void predict(InputArray src, Ptr<PredictCollector> collector) const; 00041 }; 00042 00043 // Removes duplicate elements in a given vector. 00044 template<typename _Tp> 00045 inline std::vector<_Tp> remove_dups(const std::vector<_Tp>& src) { 00046 typedef typename std::set<_Tp>::const_iterator constSetIterator; 00047 typedef typename std::vector<_Tp>::const_iterator constVecIterator; 00048 std::set<_Tp> set_elems; 00049 for (constVecIterator it = src.begin(); it != src.end(); ++it) 00050 set_elems.insert(*it); 00051 std::vector<_Tp> elems; 00052 for (constSetIterator it = set_elems.begin(); it != set_elems.end(); ++it) 00053 elems.push_back(*it); 00054 return elems; 00055 } 00056 00057 //------------------------------------------------------------------------------ 00058 // Fisherfaces 00059 //------------------------------------------------------------------------------ 00060 void Fisherfaces::train(InputArrayOfArrays src, InputArray _lbls) { 00061 if(src.total() == 0) { 00062 String error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); 00063 CV_Error(Error::StsBadArg, error_message); 00064 } else if(_lbls.getMat().type() != CV_32SC1) { 00065 String error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _lbls.type()); 00066 CV_Error(Error::StsBadArg, error_message); 00067 } 00068 // make sure data has correct size 00069 if(src.total() > 1) { 00070 for(int i = 1; i < static_cast<int>(src.total()); i++) { 00071 if(src.getMat(i-1).total() != src.getMat(i).total()) { 00072 String error_message = format("In the Fisherfaces 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()); 00073 CV_Error(Error::StsUnsupportedFormat, error_message); 00074 } 00075 } 00076 } 00077 // get data 00078 Mat labels = _lbls.getMat(); 00079 Mat data = asRowMatrix(src, CV_64FC1); 00080 // number of samples 00081 int N = data.rows; 00082 // make sure labels are passed in correct shape 00083 if(labels.total() != (size_t) N) { 00084 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()); 00085 CV_Error(Error::StsBadArg, error_message); 00086 } else if(labels.rows != 1 && labels.cols != 1) { 00087 String error_message = format("Expected the labels in a matrix with one row or column! Given dimensions are rows=%s, cols=%d.", labels.rows, labels.cols); 00088 CV_Error(Error::StsBadArg, error_message); 00089 } 00090 // clear existing model data 00091 _labels.release(); 00092 _projections.clear(); 00093 // safely copy from cv::Mat to std::vector 00094 std::vector<int> ll; 00095 for(unsigned int i = 0; i < labels.total(); i++) { 00096 ll.push_back(labels.at<int>(i)); 00097 } 00098 // get the number of unique classes 00099 int C = (int) remove_dups(ll).size(); 00100 // clip number of components to be a valid number 00101 if((_num_components <= 0) || (_num_components > (C-1))) 00102 _num_components = (C-1); 00103 // perform a PCA and keep (N-C) components 00104 PCA pca(data, Mat(), PCA::DATA_AS_ROW, (N-C)); 00105 // project the data and perform a LDA on it 00106 LDA lda(pca.project(data),labels, _num_components); 00107 // store the total mean vector 00108 _mean = pca.mean.reshape(1,1); 00109 // store labels 00110 _labels = labels.clone(); 00111 // store the eigenvalues of the discriminants 00112 lda.eigenvalues().convertTo(_eigenvalues, CV_64FC1); 00113 // Now calculate the projection matrix as pca.eigenvectors * lda.eigenvectors. 00114 // Note: OpenCV stores the eigenvectors by row, so we need to transpose it! 00115 gemm(pca.eigenvectors, lda.eigenvectors(), 1.0, Mat(), 0.0, _eigenvectors, GEMM_1_T); 00116 // store the projections of the original data 00117 for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) { 00118 Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx)); 00119 _projections.push_back(p); 00120 } 00121 } 00122 00123 void Fisherfaces::predict(InputArray _src, Ptr<PredictCollector> collector) const { 00124 Mat src = _src.getMat(); 00125 // check data alignment just for clearer exception messages 00126 if(_projections.empty()) { 00127 // throw error if no data (or simply return -1?) 00128 String error_message = "This Fisherfaces model is not computed yet. Did you call Fisherfaces::train?"; 00129 CV_Error(Error::StsBadArg, error_message); 00130 } else if(src.total() != (size_t) _eigenvectors.rows) { 00131 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()); 00132 CV_Error(Error::StsBadArg, error_message); 00133 } 00134 // project into LDA subspace 00135 Mat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1,1)); 00136 // find 1-nearest neighbor 00137 collector->init((int)_projections.size()); 00138 for (size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) { 00139 double dist = norm(_projections[sampleIdx], q, NORM_L2); 00140 int label = _labels.at<int>((int)sampleIdx); 00141 if (!collector->collect(label, dist))return; 00142 } 00143 } 00144 00145 Ptr<BasicFaceRecognizer> createFisherFaceRecognizer (int num_components, double threshold) 00146 { 00147 return makePtr<Fisherfaces>(num_components, threshold); 00148 } 00149 00150 } } 00151
Generated on Tue Jul 12 2022 14:46:42 by
