Commit 087210de authored by Vladislav Sovrasov's avatar Vladislav Sovrasov

face: refactoring of factory methods

parent aa0d8060
...@@ -318,7 +318,7 @@ public: ...@@ -318,7 +318,7 @@ public:
The suffix const means that prediction does not affect the internal model state, so the method can The suffix const means that prediction does not affect the internal model state, so the method can
be safely called from within different threads. be safely called from within different threads.
*/ */
CV_WRAP virtual void save(const String& filename) const; CV_WRAP virtual void write(const String& filename) const;
/** @brief Loads a FaceRecognizer and its model state. /** @brief Loads a FaceRecognizer and its model state.
...@@ -327,16 +327,16 @@ public: ...@@ -327,16 +327,16 @@ public:
FaceRecognizer::load(FileStorage& fs) in turn gets called by FaceRecognizer::load(FileStorage& fs) in turn gets called by
FaceRecognizer::load(const String& filename), to ease saving a model. FaceRecognizer::load(const String& filename), to ease saving a model.
*/ */
CV_WRAP virtual void load(const String& filename); CV_WRAP virtual void read(const String& filename);
/** @overload /** @overload
Saves this model to a given FileStorage. Saves this model to a given FileStorage.
@param fs The FileStorage to store this FaceRecognizer to. @param fs The FileStorage to store this FaceRecognizer to.
*/ */
virtual void save(FileStorage& fs) const = 0; virtual void write(FileStorage& fs) const = 0;
/** @overload */ /** @overload */
virtual void load(const FileStorage& fs) = 0; virtual void read(const FileNode& fn) = 0;
/** @brief Sets string info for the specified model's label. /** @brief Sets string info for the specified model's label.
......
...@@ -68,14 +68,14 @@ public: ...@@ -68,14 +68,14 @@ public:
*/ */
CV_WRAP virtual void compute(InputArray image, CV_WRAP virtual void compute(InputArray image,
OutputArray features) const = 0; OutputArray features) const = 0;
};
/** /**
* @param num_bands The number of filter bands (<=8) used for computing BIF. * @param num_bands The number of filter bands (<=8) used for computing BIF.
* @param num_rotations The number of image rotations for computing BIF. * @param num_rotations The number of image rotations for computing BIF.
* @returns Object for computing BIF. * @returns Object for computing BIF.
*/ */
CV_EXPORTS_W cv::Ptr<BIF> createBIF(int num_bands = 8, int num_rotations = 12); CV_WRAP static Ptr<BIF> create(int num_bands = 8, int num_rotations = 12);
};
} // namespace cv } // namespace cv
} // namespace face } // namespace face
......
...@@ -21,82 +21,106 @@ class CV_EXPORTS_W BasicFaceRecognizer : public FaceRecognizer ...@@ -21,82 +21,106 @@ class CV_EXPORTS_W BasicFaceRecognizer : public FaceRecognizer
{ {
public: public:
/** @see setNumComponents */ /** @see setNumComponents */
CV_WRAP virtual int getNumComponents() const = 0; CV_WRAP int getNumComponents() const;
/** @copybrief getNumComponents @see getNumComponents */ /** @copybrief getNumComponents @see getNumComponents */
CV_WRAP virtual void setNumComponents(int val) = 0; CV_WRAP void setNumComponents(int val);
/** @see setThreshold */ /** @see setThreshold */
CV_WRAP virtual double getThreshold() const = 0; CV_WRAP double getThreshold() const;
/** @copybrief getThreshold @see getThreshold */ /** @copybrief getThreshold @see getThreshold */
CV_WRAP virtual void setThreshold(double val) = 0; CV_WRAP void setThreshold(double val);
CV_WRAP virtual std::vector<cv::Mat> getProjections() const = 0; CV_WRAP std::vector<cv::Mat> getProjections() const;
CV_WRAP virtual cv::Mat getLabels() const = 0; CV_WRAP cv::Mat getLabels() const;
CV_WRAP virtual cv::Mat getEigenValues() const = 0; CV_WRAP cv::Mat getEigenValues() const;
CV_WRAP virtual cv::Mat getEigenVectors() const = 0; CV_WRAP cv::Mat getEigenVectors() const;
CV_WRAP virtual cv::Mat getMean() const = 0; CV_WRAP cv::Mat getMean() const;
virtual void read(const FileNode& fn);
virtual void write(FileStorage& fs) const;
using FaceRecognizer::read;
using FaceRecognizer::write;
protected:
int _num_components;
double _threshold;
std::vector<Mat> _projections;
Mat _labels;
Mat _eigenvectors;
Mat _eigenvalues;
Mat _mean;
};
class CV_EXPORTS_W EigenFaceRecognizer : public BasicFaceRecognizer
{
public:
/**
@param num_components The number of components (read: Eigenfaces) kept for this Principal
Component Analysis. As a hint: There's no rule how many components (read: Eigenfaces) should be
kept for good reconstruction capabilities. It is based on your input data, so experiment with the
number. Keeping 80 components should almost always be sufficient.
@param threshold The threshold applied in the prediction.
### Notes:
- Training and prediction must be done on grayscale images, use cvtColor to convert between the
color spaces.
- **THE EIGENFACES METHOD MAKES THE ASSUMPTION, THAT THE TRAINING AND TEST IMAGES ARE OF EQUAL
SIZE.** (caps-lock, because I got so many mails asking for this). You have to make sure your
input data has the correct shape, else a meaningful exception is thrown. Use resize to resize
the images.
- This model does not support updating.
### Model internal data:
- num_components see createEigenFaceRecognizer.
- threshold see createEigenFaceRecognizer.
- eigenvalues The eigenvalues for this Principal Component Analysis (ordered descending).
- eigenvectors The eigenvectors for this Principal Component Analysis (ordered by their
eigenvalue).
- mean The sample mean calculated from the training data.
- projections The projections of the training data.
- labels The threshold applied in the prediction. If the distance to the nearest neighbor is
larger than the threshold, this method returns -1.
*/
CV_WRAP static Ptr<EigenFaceRecognizer> create(int num_components = 0, double threshold = DBL_MAX);
};
class CV_EXPORTS_W FisherFaceRecognizer : public BasicFaceRecognizer
{
public:
/**
@param num_components The number of components (read: Fisherfaces) kept for this Linear
Discriminant Analysis with the Fisherfaces criterion. It's useful to keep all components, that
means the number of your classes c (read: subjects, persons you want to recognize). If you leave
this at the default (0) or set it to a value less-equal 0 or greater (c-1), it will be set to the
correct number (c-1) automatically.
@param threshold The threshold applied in the prediction. If the distance to the nearest neighbor
is larger than the threshold, this method returns -1.
### Notes:
- Training and prediction must be done on grayscale images, use cvtColor to convert between the
color spaces.
- **THE FISHERFACES METHOD MAKES THE ASSUMPTION, THAT THE TRAINING AND TEST IMAGES ARE OF EQUAL
SIZE.** (caps-lock, because I got so many mails asking for this). You have to make sure your
input data has the correct shape, else a meaningful exception is thrown. Use resize to resize
the images.
- This model does not support updating.
### Model internal data:
- num_components see createFisherFaceRecognizer.
- threshold see createFisherFaceRecognizer.
- eigenvalues The eigenvalues for this Linear Discriminant Analysis (ordered descending).
- eigenvectors The eigenvectors for this Linear Discriminant Analysis (ordered by their
eigenvalue).
- mean The sample mean calculated from the training data.
- projections The projections of the training data.
- labels The labels corresponding to the projections.
*/
CV_WRAP static Ptr<FisherFaceRecognizer> create(int num_components = 0, double threshold = DBL_MAX);
}; };
/**
@param num_components The number of components (read: Eigenfaces) kept for this Principal
Component Analysis. As a hint: There's no rule how many components (read: Eigenfaces) should be
kept for good reconstruction capabilities. It is based on your input data, so experiment with the
number. Keeping 80 components should almost always be sufficient.
@param threshold The threshold applied in the prediction.
### Notes:
- Training and prediction must be done on grayscale images, use cvtColor to convert between the
color spaces.
- **THE EIGENFACES METHOD MAKES THE ASSUMPTION, THAT THE TRAINING AND TEST IMAGES ARE OF EQUAL
SIZE.** (caps-lock, because I got so many mails asking for this). You have to make sure your
input data has the correct shape, else a meaningful exception is thrown. Use resize to resize
the images.
- This model does not support updating.
### Model internal data:
- num_components see createEigenFaceRecognizer.
- threshold see createEigenFaceRecognizer.
- eigenvalues The eigenvalues for this Principal Component Analysis (ordered descending).
- eigenvectors The eigenvectors for this Principal Component Analysis (ordered by their
eigenvalue).
- mean The sample mean calculated from the training data.
- projections The projections of the training data.
- labels The threshold applied in the prediction. If the distance to the nearest neighbor is
larger than the threshold, this method returns -1.
*/
CV_EXPORTS_W Ptr<BasicFaceRecognizer> createEigenFaceRecognizer(int num_components = 0, double threshold = DBL_MAX);
/**
@param num_components The number of components (read: Fisherfaces) kept for this Linear
Discriminant Analysis with the Fisherfaces criterion. It's useful to keep all components, that
means the number of your classes c (read: subjects, persons you want to recognize). If you leave
this at the default (0) or set it to a value less-equal 0 or greater (c-1), it will be set to the
correct number (c-1) automatically.
@param threshold The threshold applied in the prediction. If the distance to the nearest neighbor
is larger than the threshold, this method returns -1.
### Notes:
- Training and prediction must be done on grayscale images, use cvtColor to convert between the
color spaces.
- **THE FISHERFACES METHOD MAKES THE ASSUMPTION, THAT THE TRAINING AND TEST IMAGES ARE OF EQUAL
SIZE.** (caps-lock, because I got so many mails asking for this). You have to make sure your
input data has the correct shape, else a meaningful exception is thrown. Use resize to resize
the images.
- This model does not support updating.
### Model internal data:
- num_components see createFisherFaceRecognizer.
- threshold see createFisherFaceRecognizer.
- eigenvalues The eigenvalues for this Linear Discriminant Analysis (ordered descending).
- eigenvectors The eigenvectors for this Linear Discriminant Analysis (ordered by their
eigenvalue).
- mean The sample mean calculated from the training data.
- projections The projections of the training data.
- labels The labels corresponding to the projections.
*/
CV_EXPORTS_W Ptr<BasicFaceRecognizer> createFisherFaceRecognizer(int num_components = 0, double threshold = DBL_MAX);
class CV_EXPORTS_W LBPHFaceRecognizer : public FaceRecognizer class CV_EXPORTS_W LBPHFaceRecognizer : public FaceRecognizer
{ {
...@@ -123,41 +147,41 @@ public: ...@@ -123,41 +147,41 @@ public:
CV_WRAP virtual void setThreshold(double val) = 0; CV_WRAP virtual void setThreshold(double val) = 0;
CV_WRAP virtual std::vector<cv::Mat> getHistograms() const = 0; CV_WRAP virtual std::vector<cv::Mat> getHistograms() const = 0;
CV_WRAP virtual cv::Mat getLabels() const = 0; CV_WRAP virtual cv::Mat getLabels() const = 0;
};
/** /**
@param radius The radius used for building the Circular Local Binary Pattern. The greater the @param radius The radius used for building the Circular Local Binary Pattern. The greater the
radius, the radius, the
@param neighbors The number of sample points to build a Circular Local Binary Pattern from. An @param neighbors The number of sample points to build a Circular Local Binary Pattern from. An
appropriate value is to use `8` sample points. Keep in mind: the more sample points you include, appropriate value is to use `8` sample points. Keep in mind: the more sample points you include,
the higher the computational cost. the higher the computational cost.
@param grid_x The number of cells in the horizontal direction, 8 is a common value used in @param grid_x The number of cells in the horizontal direction, 8 is a common value used in
publications. The more cells, the finer the grid, the higher the dimensionality of the resulting publications. The more cells, the finer the grid, the higher the dimensionality of the resulting
feature vector. feature vector.
@param grid_y The number of cells in the vertical direction, 8 is a common value used in @param grid_y The number of cells in the vertical direction, 8 is a common value used in
publications. The more cells, the finer the grid, the higher the dimensionality of the resulting publications. The more cells, the finer the grid, the higher the dimensionality of the resulting
feature vector. feature vector.
@param threshold The threshold applied in the prediction. If the distance to the nearest neighbor @param threshold The threshold applied in the prediction. If the distance to the nearest neighbor
is larger than the threshold, this method returns -1. is larger than the threshold, this method returns -1.
### Notes: ### Notes:
- The Circular Local Binary Patterns (used in training and prediction) expect the data given as - The Circular Local Binary Patterns (used in training and prediction) expect the data given as
grayscale images, use cvtColor to convert between the color spaces. grayscale images, use cvtColor to convert between the color spaces.
- This model supports updating. - This model supports updating.
### Model internal data: ### Model internal data:
- radius see createLBPHFaceRecognizer. - radius see createLBPHFaceRecognizer.
- neighbors see createLBPHFaceRecognizer. - neighbors see createLBPHFaceRecognizer.
- grid_x see createLBPHFaceRecognizer. - grid_x see createLBPHFaceRecognizer.
- grid_y see createLBPHFaceRecognizer. - grid_y see createLBPHFaceRecognizer.
- threshold see createLBPHFaceRecognizer. - threshold see createLBPHFaceRecognizer.
- histograms Local Binary Patterns Histograms calculated from the given training data (empty if - histograms Local Binary Patterns Histograms calculated from the given training data (empty if
none was given). none was given).
- labels Labels corresponding to the calculated Local Binary Patterns Histograms. - labels Labels corresponding to the calculated Local Binary Patterns Histograms.
*/ */
CV_EXPORTS_W Ptr<LBPHFaceRecognizer> createLBPHFaceRecognizer(int radius=1, int neighbors=8, int grid_x=8, int grid_y=8, double threshold = DBL_MAX); CV_WRAP static Ptr<LBPHFaceRecognizer> create(int radius=1, int neighbors=8, int grid_x=8, int grid_y=8, double threshold = DBL_MAX);
};
//! @} //! @}
......
...@@ -121,14 +121,14 @@ int main(int argc, const char *argv[]) { ...@@ -121,14 +121,14 @@ int main(int argc, const char *argv[]) {
// 10 principal components (read Eigenfaces), then call // 10 principal components (read Eigenfaces), then call
// the factory method like this: // the factory method like this:
// //
// cv::createEigenFaceRecognizer(10); // EigenFaceRecognizer::create(10);
// //
// If you want to create a FaceRecognizer with a // If you want to create a FaceRecognizer with a
// confidennce threshold, call it with: // confidennce threshold, call it with:
// //
// cv::createEigenFaceRecognizer(10, 123.0); // EigenFaceRecognizer::create(10, 123.0);
// //
Ptr<BasicFaceRecognizer> model = createEigenFaceRecognizer(); Ptr<EigenFaceRecognizer> model = EigenFaceRecognizer::create();
for( int i = 0; i < nlabels; i++ ) for( int i = 0; i < nlabels; i++ )
model->setLabelInfo(i, labelsInfo[i]); model->setLabelInfo(i, labelsInfo[i]);
model->train(images, labels); model->train(images, labels);
......
...@@ -115,19 +115,19 @@ int main(int argc, const char *argv[]) { ...@@ -115,19 +115,19 @@ int main(int argc, const char *argv[]) {
// 10 principal components (read Eigenfaces), then call // 10 principal components (read Eigenfaces), then call
// the factory method like this: // the factory method like this:
// //
// cv::createEigenFaceRecognizer(10); // EigenFaceRecognizer::create(10);
// //
// If you want to create a FaceRecognizer with a // If you want to create a FaceRecognizer with a
// confidence threshold (e.g. 123.0), call it with: // confidence threshold (e.g. 123.0), call it with:
// //
// cv::createEigenFaceRecognizer(10, 123.0); // EigenFaceRecognizer::create(10, 123.0);
// //
// If you want to use _all_ Eigenfaces and have a threshold, // If you want to use _all_ Eigenfaces and have a threshold,
// then call the method like this: // then call the method like this:
// //
// cv::createEigenFaceRecognizer(0, 123.0); // EigenFaceRecognizer::create(0, 123.0);
// //
Ptr<BasicFaceRecognizer> model = createEigenFaceRecognizer(); Ptr<EigenFaceRecognizer> model = EigenFaceRecognizer::create();
model->train(images, labels); model->train(images, labels);
// The following line predicts the label of a given // The following line predicts the label of a given
// test image: // test image:
......
...@@ -114,7 +114,7 @@ int main(int argc, const char *argv[]) { ...@@ -114,7 +114,7 @@ int main(int argc, const char *argv[]) {
// If you just want to keep 10 Fisherfaces, then call // If you just want to keep 10 Fisherfaces, then call
// the factory method like this: // the factory method like this:
// //
// cv::createFisherFaceRecognizer(10); // FisherFaceRecognizer::create(10);
// //
// However it is not useful to discard Fisherfaces! Please // However it is not useful to discard Fisherfaces! Please
// always try to use _all_ available Fisherfaces for // always try to use _all_ available Fisherfaces for
...@@ -124,9 +124,9 @@ int main(int argc, const char *argv[]) { ...@@ -124,9 +124,9 @@ int main(int argc, const char *argv[]) {
// confidence threshold (e.g. 123.0) and use _all_ // confidence threshold (e.g. 123.0) and use _all_
// Fisherfaces, then call it with: // Fisherfaces, then call it with:
// //
// cv::createFisherFaceRecognizer(0, 123.0); // FisherFaceRecognizer::create(0, 123.0);
// //
Ptr<BasicFaceRecognizer> model = createFisherFaceRecognizer(); Ptr<FisherFaceRecognizer> model = FisherFaceRecognizer::create();
model->train(images, labels); model->train(images, labels);
// The following line predicts the label of a given // The following line predicts the label of a given
// test image: // test image:
......
...@@ -103,7 +103,7 @@ int main(int argc, const char *argv[]) { ...@@ -103,7 +103,7 @@ int main(int argc, const char *argv[]) {
// //
// cv::createLBPHFaceRecognizer(1,8,8,8,123.0) // cv::createLBPHFaceRecognizer(1,8,8,8,123.0)
// //
Ptr<LBPHFaceRecognizer> model = createLBPHFaceRecognizer(); Ptr<LBPHFaceRecognizer> model = LBPHFaceRecognizer::create();
model->train(images, labels); model->train(images, labels);
// The following line predicts the label of a given // The following line predicts the label of a given
// test image: // test image:
......
...@@ -127,7 +127,7 @@ int main(int argc, const char *argv[]) { ...@@ -127,7 +127,7 @@ int main(int argc, const char *argv[]) {
// //
// cv::createEigenFaceRecognizer(0, 123.0); // cv::createEigenFaceRecognizer(0, 123.0);
// //
Ptr<BasicFaceRecognizer> model0 = createEigenFaceRecognizer(); Ptr<EigenFaceRecognizer> model0 = EigenFaceRecognizer::create();
model0->train(images, labels); model0->train(images, labels);
// save the model to eigenfaces_at.yaml // save the model to eigenfaces_at.yaml
model0->save("eigenfaces_at.yml"); model0->save("eigenfaces_at.yml");
...@@ -135,8 +135,7 @@ int main(int argc, const char *argv[]) { ...@@ -135,8 +135,7 @@ int main(int argc, const char *argv[]) {
// //
// Now create a new Eigenfaces Recognizer // Now create a new Eigenfaces Recognizer
// //
Ptr<BasicFaceRecognizer> model1 = createEigenFaceRecognizer(); Ptr<EigenFaceRecognizer> model1 = Algorithm::load<EigenFaceRecognizer>("eigenfaces_at.yml");
model1->load("eigenfaces_at.yml");
// The following line predicts the label of a given // The following line predicts the label of a given
// test image: // test image:
int predictedLabel = model1->predict(testSample); int predictedLabel = model1->predict(testSample);
......
...@@ -79,7 +79,7 @@ int main(int argc, const char *argv[]) { ...@@ -79,7 +79,7 @@ int main(int argc, const char *argv[]) {
int im_width = images[0].cols; int im_width = images[0].cols;
int im_height = images[0].rows; int im_height = images[0].rows;
// Create a FaceRecognizer and train it on the given images: // Create a FaceRecognizer and train it on the given images:
Ptr<BasicFaceRecognizer> model = createFisherFaceRecognizer(); Ptr<FisherFaceRecognizer> model = FisherFaceRecognizer::create();
model->train(images, labels); model->train(images, labels);
// That's it for learning the Face Recognition model. You now // That's it for learning the Face Recognition model. You now
// need to create the classifier for the task of Face Detection. // need to create the classifier for the task of Face Detection.
......
...@@ -216,6 +216,6 @@ void BIFImpl::computeUnit(int unit_idx, const cv::Mat &img, ...@@ -216,6 +216,6 @@ void BIFImpl::computeUnit(int unit_idx, const cv::Mat &img,
} // namespace } // namespace
cv::Ptr<cv::face::BIF> cv::face::createBIF(int num_bands, int num_rotations) { cv::Ptr<cv::face::BIF> cv::face::BIF::create(int num_bands, int num_rotations) {
return cv::Ptr<cv::face::BIF>(new BIFImpl(num_bands, num_rotations)); return cv::Ptr<cv::face::BIF>(new BIFImpl(num_bands, num_rotations));
} }
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
* See <http://www.opensource.org/licenses/bsd-license> * See <http://www.opensource.org/licenses/bsd-license>
*/ */
#include "precomp.hpp" #include "precomp.hpp"
#include "face_basic.hpp" #include <opencv2/face.hpp>
#include "face_utils.hpp"
#include <set> #include <set>
#include <limits> #include <limits>
#include <iostream> #include <iostream>
...@@ -28,14 +29,17 @@ namespace face ...@@ -28,14 +29,17 @@ namespace face
// Turk, M., and Pentland, A. "Eigenfaces for recognition.". Journal of // Turk, M., and Pentland, A. "Eigenfaces for recognition.". Journal of
// Cognitive Neuroscience 3 (1991), 71–86. // Cognitive Neuroscience 3 (1991), 71–86.
class Eigenfaces : public BasicFaceRecognizerImpl class Eigenfaces : public EigenFaceRecognizer
{ {
public: public:
// Initializes an empty Eigenfaces model. // Initializes an empty Eigenfaces model.
Eigenfaces(int num_components = 0, double threshold = DBL_MAX) Eigenfaces(int num_components = 0, double threshold = DBL_MAX)
: BasicFaceRecognizerImpl(num_components, threshold) //: BasicFaceRecognizerImpl(num_components, threshold)
{} {
_num_components = num_components;
_threshold = threshold;
}
// Computes an Eigenfaces model with images in src and corresponding labels // Computes an Eigenfaces model with images in src and corresponding labels
// in labels. // in labels.
...@@ -122,7 +126,7 @@ void Eigenfaces::predict(InputArray _src, Ptr<PredictCollector> collector) const ...@@ -122,7 +126,7 @@ void Eigenfaces::predict(InputArray _src, Ptr<PredictCollector> collector) const
} }
} }
Ptr<BasicFaceRecognizer> createEigenFaceRecognizer(int num_components, double threshold) Ptr<EigenFaceRecognizer> EigenFaceRecognizer::create(int num_components, double threshold)
{ {
return makePtr<Eigenfaces>(num_components, threshold); return makePtr<Eigenfaces>(num_components, threshold);
} }
......
#include "opencv2/face.hpp"
#include "face_utils.hpp"
#include "precomp.hpp"
using namespace cv;
using namespace face;
int BasicFaceRecognizer::getNumComponents() const
{
return _num_components;
}
void BasicFaceRecognizer::setNumComponents(int val)
{
_num_components = val;
}
double BasicFaceRecognizer::getThreshold() const
{
return _threshold;
}
void BasicFaceRecognizer::setThreshold(double val)
{
_threshold = val;
}
std::vector<cv::Mat> BasicFaceRecognizer::getProjections() const
{
return _projections;
}
cv::Mat BasicFaceRecognizer::getLabels() const
{
return _labels;
}
cv::Mat BasicFaceRecognizer::getEigenValues() const
{
return _eigenvalues;
}
cv::Mat BasicFaceRecognizer::getEigenVectors() const
{
return _eigenvectors;
}
cv::Mat BasicFaceRecognizer::getMean() const
{
return _mean;
}
void BasicFaceRecognizer::read(const FileNode& fs)
{
//read matrices
fs["num_components"] >> _num_components;
fs["mean"] >> _mean;
fs["eigenvalues"] >> _eigenvalues;
fs["eigenvectors"] >> _eigenvectors;
// read sequences
readFileNodeList(fs["projections"], _projections);
fs["labels"] >> _labels;
const FileNode& fn = fs["labelsInfo"];
if (fn.type() == FileNode::SEQ)
{
_labelsInfo.clear();
for (FileNodeIterator it = fn.begin(); it != fn.end();)
{
LabelInfo item;
it >> item;
_labelsInfo.insert(std::make_pair(item.label, item.value));
}
}
}
void BasicFaceRecognizer::write(FileStorage& fs) const
{
// write matrices
fs << "num_components" << _num_components;
fs << "mean" << _mean;
fs << "eigenvalues" << _eigenvalues;
fs << "eigenvectors" << _eigenvectors;
// write sequences
writeFileNodeList(fs, "projections", _projections);
fs << "labels" << _labels;
fs << "labelsInfo" << "[";
for (std::map<int, String>::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++)
fs << LabelInfo(it->first, it->second);
fs << "]";
}
#ifndef __OPENCV_FACE_BASIC_HPP // This file is part of OpenCV project.
#define __OPENCV_FACE_BASIC_HPP // It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "opencv2/face.hpp" #ifndef __OPENCV_FACE_UTILS_HPP
#include "precomp.hpp" #define __OPENCV_FACE_UTILS_HPP
#include <set> #include "precomp.hpp"
#include <limits>
#include <iostream>
using namespace cv; using namespace cv;
// Reads a sequence from a FileNode::SEQ with type _Tp into a result vector.
template<typename _Tp>
inline void readFileNodeList(const FileNode& fn, std::vector<_Tp>& result) {
if (fn.type() == FileNode::SEQ) {
for (FileNodeIterator it = fn.begin(); it != fn.end();) {
_Tp item;
it >> item;
result.push_back(item);
}
}
}
// Writes the a list of given items to a cv::FileStorage.
template<typename _Tp>
inline void writeFileNodeList(FileStorage& fs, const String& name,
const std::vector<_Tp>& items) {
// typedefs
typedef typename std::vector<_Tp>::const_iterator constVecIterator;
// write the elements in item to fs
fs << name << "[";
for (constVecIterator it = items.begin(); it != items.end(); ++it) {
fs << *it;
}
fs << "]";
}
inline Mat asRowMatrix(InputArrayOfArrays src, int rtype, double alpha=1, double beta=0) { inline Mat asRowMatrix(InputArrayOfArrays src, int rtype, double alpha=1, double beta=0) {
// make sure the input data is a vector of matrices or vector of vector // make sure the input data is a vector of matrices or vector of vector
if(src.kind() != _InputArray::STD_VECTOR_MAT && src.kind() != _InputArray::STD_VECTOR_VECTOR) { if(src.kind() != _InputArray::STD_VECTOR_MAT && src.kind() != _InputArray::STD_VECTOR_VECTOR) {
...@@ -70,6 +43,32 @@ inline Mat asRowMatrix(InputArrayOfArrays src, int rtype, double alpha=1, double ...@@ -70,6 +43,32 @@ inline Mat asRowMatrix(InputArrayOfArrays src, int rtype, double alpha=1, double
return data; return data;
} }
// Reads a sequence from a FileNode::SEQ with type _Tp into a result vector.
template<typename _Tp>
inline void readFileNodeList(const FileNode& fn, std::vector<_Tp>& result) {
if (fn.type() == FileNode::SEQ) {
for (FileNodeIterator it = fn.begin(); it != fn.end();) {
_Tp item;
it >> item;
result.push_back(item);
}
}
}
// Writes the a list of given items to a cv::FileStorage.
template<typename _Tp>
inline void writeFileNodeList(FileStorage& fs, const String& name,
const std::vector<_Tp>& items) {
// typedefs
typedef typename std::vector<_Tp>::const_iterator constVecIterator;
// write the elements in item to fs
fs << name << "[";
for (constVecIterator it = items.begin(); it != items.end(); ++it) {
fs << *it;
}
fs << "]";
}
// Utility structure to load/save face label info (a pair of int and string) via FileStorage // Utility structure to load/save face label info (a pair of int and string) via FileStorage
struct LabelInfo struct LabelInfo
{ {
...@@ -106,70 +105,4 @@ inline void read(const cv::FileNode& node, LabelInfo& x, const LabelInfo& defaul ...@@ -106,70 +105,4 @@ inline void read(const cv::FileNode& node, LabelInfo& x, const LabelInfo& defaul
x.read(node); x.read(node);
} }
#endif
class BasicFaceRecognizerImpl : public cv::face::BasicFaceRecognizer
{
public:
BasicFaceRecognizerImpl(int num_components = 0, double threshold = DBL_MAX)
: _num_components(num_components), _threshold(threshold)
{}
void load(const FileStorage& fs)
{
//read matrices
fs["num_components"] >> _num_components;
fs["mean"] >> _mean;
fs["eigenvalues"] >> _eigenvalues;
fs["eigenvectors"] >> _eigenvectors;
// read sequences
readFileNodeList(fs["projections"], _projections);
fs["labels"] >> _labels;
const FileNode& fn = fs["labelsInfo"];
if (fn.type() == FileNode::SEQ)
{
_labelsInfo.clear();
for (FileNodeIterator it = fn.begin(); it != fn.end();)
{
LabelInfo item;
it >> item;
_labelsInfo.insert(std::make_pair(item.label, item.value));
}
}
}
void save(FileStorage& fs) const
{
// write matrices
fs << "num_components" << _num_components;
fs << "mean" << _mean;
fs << "eigenvalues" << _eigenvalues;
fs << "eigenvectors" << _eigenvectors;
// write sequences
writeFileNodeList(fs, "projections", _projections);
fs << "labels" << _labels;
fs << "labelsInfo" << "[";
for (std::map<int, String>::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++)
fs << LabelInfo(it->first, it->second);
fs << "]";
}
CV_IMPL_PROPERTY(int, NumComponents, _num_components)
CV_IMPL_PROPERTY(double, Threshold, _threshold)
CV_IMPL_PROPERTY_RO(std::vector<cv::Mat>, Projections, _projections)
CV_IMPL_PROPERTY_RO(cv::Mat, Labels, _labels)
CV_IMPL_PROPERTY_RO(cv::Mat, EigenValues, _eigenvalues)
CV_IMPL_PROPERTY_RO(cv::Mat, EigenVectors, _eigenvectors)
CV_IMPL_PROPERTY_RO(cv::Mat, Mean, _mean)
protected:
int _num_components;
double _threshold;
std::vector<Mat> _projections;
Mat _labels;
Mat _eigenvectors;
Mat _eigenvalues;
Mat _mean;
};
#endif // __OPENCV_FACE_BASIC_HPP
...@@ -54,21 +54,21 @@ void FaceRecognizer::update(InputArrayOfArrays src, InputArray labels) ...@@ -54,21 +54,21 @@ void FaceRecognizer::update(InputArrayOfArrays src, InputArray labels)
CV_Error(Error::StsNotImplemented, error_msg); CV_Error(Error::StsNotImplemented, error_msg);
} }
void FaceRecognizer::load(const String &filename) void FaceRecognizer::read(const String &filename)
{ {
FileStorage fs(filename, FileStorage::READ); FileStorage fs(filename, FileStorage::READ);
if (!fs.isOpened()) if (!fs.isOpened())
CV_Error(Error::StsError, "File can't be opened for reading!"); CV_Error(Error::StsError, "File can't be opened for reading!");
this->load(fs); this->read(fs.root());
fs.release(); fs.release();
} }
void FaceRecognizer::save(const String &filename) const void FaceRecognizer::write(const String &filename) const
{ {
FileStorage fs(filename, FileStorage::WRITE); FileStorage fs(filename, FileStorage::WRITE);
if (!fs.isOpened()) if (!fs.isOpened())
CV_Error(Error::StsError, "File can't be opened for writing!"); CV_Error(Error::StsError, "File can't be opened for writing!");
this->save(fs); this->write(fs);
fs.release(); fs.release();
} }
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
* See <http://www.opensource.org/licenses/bsd-license> * See <http://www.opensource.org/licenses/bsd-license>
*/ */
#include "precomp.hpp" #include "precomp.hpp"
#include "face_basic.hpp" #include <opencv2/face.hpp>
#include "face_utils.hpp"
namespace cv { namespace face { namespace cv { namespace face {
...@@ -24,13 +25,16 @@ namespace cv { namespace face { ...@@ -24,13 +25,16 @@ namespace cv { namespace face {
// faces: Recognition using class specific linear projection.". IEEE // faces: Recognition using class specific linear projection.". IEEE
// Transactions on Pattern Analysis and Machine Intelligence 19, 7 (1997), // Transactions on Pattern Analysis and Machine Intelligence 19, 7 (1997),
// 711–720. // 711–720.
class Fisherfaces: public BasicFaceRecognizerImpl class Fisherfaces: public FisherFaceRecognizer
{ {
public: public:
// Initializes an empty Fisherfaces model. // Initializes an empty Fisherfaces model.
Fisherfaces(int num_components = 0, double threshold = DBL_MAX) Fisherfaces(int num_components = 0, double threshold = DBL_MAX)
: BasicFaceRecognizerImpl(num_components, threshold) //: BasicFaceRecognizer(num_components, threshold)
{ } {
_num_components = num_components;
_threshold = threshold;
}
// Computes a Fisherfaces model with images in src and corresponding labels // Computes a Fisherfaces model with images in src and corresponding labels
// in labels. // in labels.
...@@ -142,7 +146,7 @@ void Fisherfaces::predict(InputArray _src, Ptr<PredictCollector> collector) cons ...@@ -142,7 +146,7 @@ void Fisherfaces::predict(InputArray _src, Ptr<PredictCollector> collector) cons
} }
} }
Ptr<BasicFaceRecognizer> createFisherFaceRecognizer(int num_components, double threshold) Ptr<FisherFaceRecognizer> FisherFaceRecognizer::create(int num_components, double threshold)
{ {
return makePtr<Fisherfaces>(num_components, threshold); return makePtr<Fisherfaces>(num_components, threshold);
} }
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
*/ */
#include "precomp.hpp" #include "precomp.hpp"
#include "opencv2/face.hpp" #include "opencv2/face.hpp"
#include "face_basic.hpp" #include "face_utils.hpp"
namespace cv { namespace face { namespace cv { namespace face {
...@@ -46,8 +46,8 @@ private: ...@@ -46,8 +46,8 @@ private:
public: public:
using FaceRecognizer::save; using FaceRecognizer::read;
using FaceRecognizer::load; using FaceRecognizer::write;
// Initializes this LBPH Model. The current implementation is rather fixed // Initializes this LBPH Model. The current implementation is rather fixed
// as it uses the Extended Local Binary Patterns per default. // as it uses the Extended Local Binary Patterns per default.
...@@ -94,11 +94,11 @@ public: ...@@ -94,11 +94,11 @@ public:
// Send all predict results to caller side for custom result handling // Send all predict results to caller side for custom result handling
void predict(InputArray src, Ptr<PredictCollector> collector) const; void predict(InputArray src, Ptr<PredictCollector> collector) const;
// See FaceRecognizer::load. // See FaceRecognizer::write.
void load(const FileStorage& fs); void read(const FileNode& fn);
// See FaceRecognizer::save. // See FaceRecognizer::save.
void save(FileStorage& fs) const; void write(FileStorage& fs) const;
CV_IMPL_PROPERTY(int, GridX, _grid_x) CV_IMPL_PROPERTY(int, GridX, _grid_x)
CV_IMPL_PROPERTY(int, GridY, _grid_y) CV_IMPL_PROPERTY(int, GridY, _grid_y)
...@@ -110,7 +110,7 @@ public: ...@@ -110,7 +110,7 @@ public:
}; };
void LBPH::load(const FileStorage& fs) { void LBPH::read(const FileNode& fs) {
fs["radius"] >> _radius; fs["radius"] >> _radius;
fs["neighbors"] >> _neighbors; fs["neighbors"] >> _neighbors;
fs["grid_x"] >> _grid_x; fs["grid_x"] >> _grid_x;
...@@ -132,7 +132,7 @@ void LBPH::load(const FileStorage& fs) { ...@@ -132,7 +132,7 @@ void LBPH::load(const FileStorage& fs) {
} }
// See FaceRecognizer::save. // See FaceRecognizer::save.
void LBPH::save(FileStorage& fs) const { void LBPH::write(FileStorage& fs) const {
fs << "radius" << _radius; fs << "radius" << _radius;
fs << "neighbors" << _neighbors; fs << "neighbors" << _neighbors;
fs << "grid_x" << _grid_x; fs << "grid_x" << _grid_x;
...@@ -407,11 +407,10 @@ void LBPH::predict(InputArray _src, Ptr<PredictCollector> collector) const { ...@@ -407,11 +407,10 @@ void LBPH::predict(InputArray _src, Ptr<PredictCollector> collector) const {
} }
} }
Ptr<LBPHFaceRecognizer> createLBPHFaceRecognizer(int radius, int neighbors, Ptr<LBPHFaceRecognizer> LBPHFaceRecognizer::create(int radius, int neighbors,
int grid_x, int grid_y, double threshold) int grid_x, int grid_y, double threshold)
{ {
return makePtr<LBPH>(radius, neighbors, grid_x, grid_y, threshold); return makePtr<LBPH>(radius, neighbors, grid_x, grid_y, threshold);
} }
}} }}
...@@ -49,10 +49,8 @@ ...@@ -49,10 +49,8 @@
#include "opencv2/core/private.hpp" #include "opencv2/core/private.hpp"
#include "opencv2/core/persistence.hpp" #include "opencv2/core/persistence.hpp"
#include <map> #include <map>
#include <iostream>
#include <set> #include <set>
#include <limits> #include <limits>
#include <iostream>
#endif #endif
...@@ -40,27 +40,27 @@ the use of this software, even if advised of the possibility of such damage. ...@@ -40,27 +40,27 @@ the use of this software, even if advised of the possibility of such damage.
TEST(CV_Face_BIF, can_create_default) { TEST(CV_Face_BIF, can_create_default) {
cv::Ptr<cv::face::BIF> bif; cv::Ptr<cv::face::BIF> bif;
EXPECT_NO_THROW(bif = cv::face::createBIF()); EXPECT_NO_THROW(bif = cv::face::BIF::create());
EXPECT_FALSE(bif.empty()); EXPECT_FALSE(bif.empty());
} }
TEST(CV_Face_BIF, fails_when_zero_bands) { TEST(CV_Face_BIF, fails_when_zero_bands) {
EXPECT_ANY_THROW(cv::face::createBIF(0)); EXPECT_ANY_THROW(cv::face::BIF::create(0));
} }
TEST(CV_Face_BIF, fails_when_too_many_bands) { TEST(CV_Face_BIF, fails_when_too_many_bands) {
EXPECT_ANY_THROW(cv::face::createBIF(9)); EXPECT_ANY_THROW(cv::face::BIF::create(9));
} }
TEST(CV_Face_BIF, fails_when_zero_rotations) { TEST(CV_Face_BIF, fails_when_zero_rotations) {
EXPECT_ANY_THROW(cv::face::createBIF(8, 0)); EXPECT_ANY_THROW(cv::face::BIF::create(8, 0));
} }
TEST(CV_Face_BIF, can_compute) { TEST(CV_Face_BIF, can_compute) {
cv::Mat image(60, 60, CV_32F); cv::Mat image(60, 60, CV_32F);
cv::theRNG().fill(image, cv::RNG::UNIFORM, -1, 1); cv::theRNG().fill(image, cv::RNG::UNIFORM, -1, 1);
cv::Ptr<cv::face::BIF> bif = cv::face::createBIF(); cv::Ptr<cv::face::BIF> bif = cv::face::BIF::create();
cv::Mat fea; cv::Mat fea;
EXPECT_NO_THROW(bif->compute(image, fea)); EXPECT_NO_THROW(bif->compute(image, fea));
EXPECT_EQ(cv::Size(1, 13188), fea.size()); EXPECT_EQ(cv::Size(1, 13188), fea.size());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment