Commit 41c932f3 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

FaceRecognizer class is now derived from Algorithm, therefore it's possible to…

FaceRecognizer class is now derived from Algorithm, therefore it's possible to set and retrieve the parameters using conventional Algorithm::set and Algorithm::get methods
parent fd68cc76
......@@ -918,7 +918,7 @@ namespace cv
void lda(InputArray src, InputArray labels);
};
class CV_EXPORTS FaceRecognizer
class CV_EXPORTS FaceRecognizer : public Algorithm
{
public:
//! virtual destructor
......@@ -970,6 +970,8 @@ namespace cv
};
CV_EXPORTS void applyColorMap(InputArray src, OutputArray dst, int colormap);
CV_EXPORTS bool initModule_contrib();
}
......
......@@ -90,7 +90,7 @@ class Eigenfaces : public FaceRecognizer
private:
int _num_components;
vector<Mat> _projections;
vector<int> _labels;
Mat _labels;
Mat _eigenvectors;
Mat _eigenvalues;
Mat _mean;
......@@ -125,17 +125,7 @@ public:
// See FaceRecognizer::save.
void save(FileStorage& fs) const;
// Returns the eigenvectors of this PCA.
Mat eigenvectors() const { return _eigenvectors; }
// Returns the eigenvalues of this PCA.
Mat eigenvalues() const { return _eigenvalues; }
// Returns the sample mean of this PCA.
Mat mean() const { return _mean; }
// Returns the number of components used in this PCA.
int num_components() const { return _num_components; }
AlgorithmInfo* info() const;
};
// Belhumeur, P. N., Hespanha, J., and Kriegman, D. "Eigenfaces vs. Fisher-
......@@ -150,7 +140,7 @@ private:
Mat _eigenvalues;
Mat _mean;
vector<Mat> _projections;
vector<int> _labels;
Mat _labels;
public:
using FaceRecognizer::save;
......@@ -185,17 +175,7 @@ public:
// See FaceRecognizer::save.
virtual void save(FileStorage& fs) const;
// Returns the eigenvectors of this Fisherfaces model.
Mat eigenvectors() const { return _eigenvectors; }
// Returns the eigenvalues of this Fisherfaces model.
Mat eigenvalues() const { return _eigenvalues; }
// Returns the sample mean of this Fisherfaces model.
Mat mean() const { return _eigenvalues; }
// Returns the number of components used in this Fisherfaces model.
int num_components() const { return _num_components; }
AlgorithmInfo* info() const;
};
// Face Recognition based on Local Binary Patterns.
......@@ -217,7 +197,7 @@ private:
int _neighbors;
vector<Mat> _histograms;
vector<int> _labels;
Mat _labels;
public:
using FaceRecognizer::save;
......@@ -271,6 +251,7 @@ public:
int grid_x() const { return _grid_x; }
int grid_y() const { return _grid_y; }
AlgorithmInfo* info() const;
};
......@@ -302,7 +283,8 @@ void Eigenfaces::train(InputArray src, InputArray _lbls) {
if(_lbls.getMat().type() != CV_32SC1)
CV_Error(CV_StsUnsupportedFormat, "Labels must be given as integer (CV_32SC1).");
// get labels
vector<int> labels = _lbls.getMat();
Mat labels = _lbls.getMat();
CV_Assert( labels.type() == CV_32S && (labels.cols == 1 || labels.rows == 1));
// observations in row
Mat data = asRowMatrix(src, CV_64FC1);
// number of samples
......@@ -310,7 +292,7 @@ void Eigenfaces::train(InputArray src, InputArray _lbls) {
// dimensionality of data
//int d = data.cols;
// assert there are as much samples as labels
if((size_t)n != labels.size())
if((size_t)n != labels.total())
CV_Error(CV_StsBadArg, "The number of samples must equal the number of labels!");
// clip number of components to be valid
if((_num_components <= 0) || (_num_components > n))
......@@ -321,7 +303,7 @@ void Eigenfaces::train(InputArray src, InputArray _lbls) {
_mean = pca.mean.reshape(1,1); // store the mean vector
_eigenvalues = pca.eigenvalues.clone(); // eigenvalues by row
transpose(pca.eigenvectors, _eigenvectors); // eigenvectors by column
_labels = labels; // store labels for prediction
labels.copyTo(_labels); // store labels for prediction
// save projections
for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) {
Mat p = subspaceProject(_eigenvectors, _mean, data.row(sampleIdx));
......@@ -340,7 +322,7 @@ int Eigenfaces::predict(InputArray _src) const {
double dist = norm(_projections[sampleIdx], q, NORM_L2);
if(dist < minDist) {
minDist = dist;
minClass = _labels[sampleIdx];
minClass = _labels.at<int>(sampleIdx);
}
}
return minClass;
......@@ -354,7 +336,7 @@ void Eigenfaces::load(const FileStorage& fs) {
fs["eigenvectors"] >> _eigenvectors;
// read sequences
readFileNodeList(fs["projections"], _projections);
readFileNodeList(fs["labels"], _labels);
fs["labels"] >> _labels;
}
void Eigenfaces::save(FileStorage& fs) const {
......@@ -365,7 +347,7 @@ void Eigenfaces::save(FileStorage& fs) const {
fs << "eigenvectors" << _eigenvectors;
// write sequences
writeFileNodeList(fs, "projections", _projections);
writeFileNodeList(fs, "labels", _labels);
fs << "labels" << _labels;
}
//------------------------------------------------------------------------------
......@@ -375,16 +357,22 @@ void Fisherfaces::train(InputArray src, InputArray _lbls) {
if(_lbls.getMat().type() != CV_32SC1)
CV_Error(CV_StsUnsupportedFormat, "Labels must be given as integer (CV_32SC1).");
// get data
vector<int> labels = _lbls.getMat();
Mat labels = _lbls.getMat();
Mat data = asRowMatrix(src, CV_64FC1);
CV_Assert( labels.type() == CV_32S && (labels.cols == 1 || labels.rows == 1));
// dimensionality
int N = data.rows; // number of samples
//int D = data.cols; // dimension of samples
// assert correct data alignment
if(labels.size() != (size_t)N)
if(labels.total() != (size_t)N)
CV_Error(CV_StsUnsupportedFormat, "Labels must be given as integer (CV_32SC1).");
// compute the Fisherfaces
int C = (int)remove_dups(labels).size(); // number of unique classes
vector<int> ll;
labels.copyTo(ll);
int C = (int)remove_dups(ll).size(); // number of unique classes
// clip number of components to be a valid number
if((_num_components <= 0) || (_num_components > (C-1)))
_num_components = (C-1);
......@@ -395,7 +383,7 @@ void Fisherfaces::train(InputArray src, InputArray _lbls) {
// store the total mean vector
_mean = pca.mean.reshape(1,1);
// store labels
_labels = labels;
labels.copyTo(_labels);
// store the eigenvalues of the discriminants
lda.eigenvalues().convertTo(_eigenvalues, CV_64FC1);
// Now calculate the projection matrix as pca.eigenvectors * lda.eigenvectors.
......@@ -419,7 +407,7 @@ int Fisherfaces::predict(InputArray _src) const {
double dist = norm(_projections[sampleIdx], q, NORM_L2);
if(dist < minDist) {
minDist = dist;
minClass = _labels[sampleIdx];
minClass = _labels.at<int>(sampleIdx);
}
}
return minClass;
......@@ -435,7 +423,7 @@ void Fisherfaces::load(const FileStorage& fs) {
fs["eigenvectors"] >> _eigenvectors;
// read sequences
readFileNodeList(fs["projections"], _projections);
readFileNodeList(fs["labels"], _labels);
fs["labels"] >> _labels;
}
// See FaceRecognizer::save.
......@@ -447,7 +435,7 @@ void Fisherfaces::save(FileStorage& fs) const {
fs << "eigenvectors" << _eigenvectors;
// write sequences
writeFileNodeList(fs, "projections", _projections);
writeFileNodeList(fs, "labels", _labels);
fs << "labels" << _labels;
}
//------------------------------------------------------------------------------
// LBPH
......@@ -630,7 +618,7 @@ void LBPH::load(const FileStorage& fs) {
fs["grid_y"] >> _grid_y;
//read matrices
readFileNodeList(fs["histograms"], _histograms);
readFileNodeList(fs["labels"], _labels);
fs["labels"] >> _labels;
}
// See FaceRecognizer::save.
......@@ -641,7 +629,7 @@ void LBPH::save(FileStorage& fs) const {
fs << "grid_y" << _grid_y;
// write matrices
writeFileNodeList(fs, "histograms", _histograms);
writeFileNodeList(fs, "labels", _labels);
fs << "labels" << _labels;
}
void LBPH::train(InputArray _src, InputArray _lbls) {
......@@ -651,11 +639,12 @@ void LBPH::train(InputArray _src, InputArray _lbls) {
vector<Mat> src;
_src.getMatVector(src);
// turn the label matrix into a vector
vector<int> labels = _lbls.getMat();
if(labels.size() != src.size())
Mat labels = _lbls.getMat();
CV_Assert( labels.type() == CV_32S && (labels.cols == 1 || labels.rows == 1));
if(labels.total() != src.size())
CV_Error(CV_StsUnsupportedFormat, "The number of labels must equal the number of samples.");
// store given labels
_labels = labels;
labels.copyTo(_labels);
// store the spatial histograms of the original data
for(size_t sampleIdx = 0; sampleIdx < src.size(); sampleIdx++) {
// calculate lbp image
......@@ -690,7 +679,7 @@ int LBPH::predict(InputArray _src) const {
double dist = compareHist(_histograms[sampleIdx], query, CV_COMP_CHISQR);
if(dist < minDist) {
minDist = dist;
minClass = _labels[sampleIdx];
minClass = _labels.at<int>(sampleIdx);
}
}
return minClass;
......@@ -713,4 +702,34 @@ Ptr<FaceRecognizer> createLBPHFaceRecognizer(int radius, int neighbors,
return new LBPH(radius, neighbors, grid_x, grid_y);
}
CV_INIT_ALGORITHM(Eigenfaces, "FaceRecognizer.Eigenfaces",
obj.info()->addParam(obj, "ncomponents", obj._num_components);
obj.info()->addParam(obj, "projections", obj._projections, true);
obj.info()->addParam(obj, "labels", obj._labels, true);
obj.info()->addParam(obj, "eigenvectors", obj._eigenvectors, true);
obj.info()->addParam(obj, "eigenvalues", obj._eigenvalues, true);
obj.info()->addParam(obj, "mean", obj._mean, true));
CV_INIT_ALGORITHM(Fisherfaces, "FaceRecognizer.Fisherfaces",
obj.info()->addParam(obj, "ncomponents", obj._num_components);
obj.info()->addParam(obj, "projections", obj._projections, true);
obj.info()->addParam(obj, "labels", obj._labels, true);
obj.info()->addParam(obj, "eigenvectors", obj._eigenvectors, true);
obj.info()->addParam(obj, "eigenvalues", obj._eigenvalues, true);
obj.info()->addParam(obj, "mean", obj._mean, true));
CV_INIT_ALGORITHM(LBPH, "FaceRecognizer.LBPH",
obj.info()->addParam(obj, "radius", obj._radius);
obj.info()->addParam(obj, "neighbors", obj._neighbors);
obj.info()->addParam(obj, "grid_x", obj._grid_x);
obj.info()->addParam(obj, "grid_y", obj._grid_y);
obj.info()->addParam(obj, "histograms", obj._histograms, true);
obj.info()->addParam(obj, "labels", obj._labels, true));
bool initModule_contrib()
{
Ptr<Algorithm> efaces = createEigenfaces(), ffaces = createFisherfaces(), lbph = createLBPH();
return efaces->info() != 0 && ffaces->info() != 0 && lbph->info() != 0;
}
}
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