diff --git a/modules/bgsegm/src/bgfg_gaussmix.cpp b/modules/bgsegm/src/bgfg_gaussmix.cpp index 62248fbf5..9e9d448da 100644 --- a/modules/bgsegm/src/bgfg_gaussmix.cpp +++ b/modules/bgsegm/src/bgfg_gaussmix.cpp @@ -122,8 +122,6 @@ public: bgmodel = Scalar::all(0); } - virtual AlgorithmInfo* info() const { return 0; } - virtual void getBackgroundImage(OutputArray) const { CV_Error( Error::StsNotImplemented, "" ); diff --git a/modules/bgsegm/src/bgfg_gmg.cpp b/modules/bgsegm/src/bgfg_gmg.cpp index cb6900844..5f5f60f7b 100644 --- a/modules/bgsegm/src/bgfg_gmg.cpp +++ b/modules/bgsegm/src/bgfg_gmg.cpp @@ -81,8 +81,6 @@ public: { } - virtual AlgorithmInfo* info() const { return 0; } - /** * Validate parameters and set up data structures for appropriate image size. * Must call before running on data. diff --git a/modules/datasets/samples/ar_hmdb_benchmark.cpp b/modules/datasets/samples/ar_hmdb_benchmark.cpp index f9412ee74..a276ee898 100644 --- a/modules/datasets/samples/ar_hmdb_benchmark.cpp +++ b/modules/datasets/samples/ar_hmdb_benchmark.cpp @@ -188,17 +188,16 @@ int main(int argc, char *argv[]) fillData(path, curr, flann_index, trainData, trainLabels); printf("train svm\n"); - SVM::Params params; - params.svmType = SVM::C_SVC; - params.kernelType = SVM::POLY; //SVM::RBF; - params.degree = 0.5; - params.gamma = 1; - params.coef0 = 1; - params.C = 1; - params.nu = 0.5; - params.p = 0; - params.termCrit = TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1000, 0.01); - Ptr svm = SVM::create(params); + Ptr svm = SVM::create(); + svm->setType(SVM::C_SVC); + svm->setKernel(SVM::POLY); //SVM::RBF; + svm->setDegree(0.5); + svm->setGamma(1); + svm->setCoef0(1); + svm->setC(1); + svm->setNu(0.5); + svm->setP(0); + svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1000, 0.01)); svm->train(trainData, ROW_SAMPLE, trainLabels); // prepare to predict diff --git a/modules/face/include/opencv2/face.hpp b/modules/face/include/opencv2/face.hpp index be6decd5f..a659fddc7 100644 --- a/modules/face/include/opencv2/face.hpp +++ b/modules/face/include/opencv2/face.hpp @@ -39,8 +39,6 @@ the use of this software, even if advised of the possibility of such damage. #ifndef __OPENCV_FACE_HPP__ #define __OPENCV_FACE_HPP__ -#include "opencv2/face/facerec.hpp" - /** @defgroup face Face Recognition @@ -49,4 +47,314 @@ the use of this software, even if advised of the possibility of such damage. */ +#include "opencv2/core.hpp" +#include + +namespace cv { namespace face { + +//! @addtogroup face +//! @{ + +/** @brief Abstract base class for all face recognition models + +All face recognition models in OpenCV are derived from the abstract base class FaceRecognizer, which +provides a unified access to all face recongition algorithms in OpenCV. + +### Description + +I'll go a bit more into detail explaining FaceRecognizer, because it doesn't look like a powerful +interface at first sight. But: Every FaceRecognizer is an Algorithm, so you can easily get/set all +model internals (if allowed by the implementation). Algorithm is a relatively new OpenCV concept, +which is available since the 2.4 release. I suggest you take a look at its description. + +Algorithm provides the following features for all derived classes: + +- So called “virtual constructor”. That is, each Algorithm derivative is registered at program + start and you can get the list of registered algorithms and create instance of a particular + algorithm by its name (see Algorithm::create). If you plan to add your own algorithms, it is + good practice to add a unique prefix to your algorithms to distinguish them from other + algorithms. +- Setting/Retrieving algorithm parameters by name. If you used video capturing functionality from + OpenCV highgui module, you are probably familar with cv::cvSetCaptureProperty, +ocvcvGetCaptureProperty, VideoCapture::set and VideoCapture::get. Algorithm provides similar + method where instead of integer id's you specify the parameter names as text Strings. See + Algorithm::set and Algorithm::get for details. +- Reading and writing parameters from/to XML or YAML files. Every Algorithm derivative can store + all its parameters and then read them back. There is no need to re-implement it each time. + +Moreover every FaceRecognizer supports the: + +- **Training** of a FaceRecognizer with FaceRecognizer::train on a given set of images (your face + database!). +- **Prediction** of a given sample image, that means a face. The image is given as a Mat. +- **Loading/Saving** the model state from/to a given XML or YAML. +- **Setting/Getting labels info**, that is stored as a string. String labels info is useful for + keeping names of the recognized people. + +@note When using the FaceRecognizer interface in combination with Python, please stick to Python 2. +Some underlying scripts like create_csv will not work in other versions, like Python 3. Setting the +Thresholds +++++++++++++++++++++++ + +Sometimes you run into the situation, when you want to apply a threshold on the prediction. A common +scenario in face recognition is to tell, whether a face belongs to the training dataset or if it is +unknown. You might wonder, why there's no public API in FaceRecognizer to set the threshold for the +prediction, but rest assured: It's supported. It just means there's no generic way in an abstract +class to provide an interface for setting/getting the thresholds of *every possible* FaceRecognizer +algorithm. The appropriate place to set the thresholds is in the constructor of the specific +FaceRecognizer and since every FaceRecognizer is a Algorithm (see above), you can get/set the +thresholds at runtime! + +Here is an example of setting a threshold for the Eigenfaces method, when creating the model: + +@code +// Let's say we want to keep 10 Eigenfaces and have a threshold value of 10.0 +int num_components = 10; +double threshold = 10.0; +// Then if you want to have a cv::FaceRecognizer with a confidence threshold, +// create the concrete implementation with the appropiate parameters: +Ptr model = createEigenFaceRecognizer(num_components, threshold); +@endcode + +Sometimes it's impossible to train the model, just to experiment with threshold values. Thanks to +Algorithm it's possible to set internal model thresholds during runtime. Let's see how we would +set/get the prediction for the Eigenface model, we've created above: + +@code +// The following line reads the threshold from the Eigenfaces model: +double current_threshold = model->getDouble("threshold"); +// And this line sets the threshold to 0.0: +model->set("threshold", 0.0); +@endcode + +If you've set the threshold to 0.0 as we did above, then: + +@code +// +Mat img = imread("person1/3.jpg", CV_LOAD_IMAGE_GRAYSCALE); +// Get a prediction from the model. Note: We've set a threshold of 0.0 above, +// since the distance is almost always larger than 0.0, you'll get -1 as +// label, which indicates, this face is unknown +int predicted_label = model->predict(img); +// ... +@endcode + +is going to yield -1 as predicted label, which states this face is unknown. + +### Getting the name of a FaceRecognizer + +Since every FaceRecognizer is a Algorithm, you can use Algorithm::name to get the name of a +FaceRecognizer: + +@code +// Create a FaceRecognizer: +Ptr model = createEigenFaceRecognizer(); +// And here's how to get its name: +String name = model->name(); +@endcode + + */ +class CV_EXPORTS_W FaceRecognizer : public Algorithm +{ +public: + /** @brief Trains a FaceRecognizer with given data and associated labels. + + @param src The training images, that means the faces you want to learn. The data has to be + given as a vector\. + @param labels The labels corresponding to the images have to be given either as a vector\ + or a + + The following source code snippet shows you how to learn a Fisherfaces model on a given set of + images. The images are read with imread and pushed into a std::vector\. The labels of each + image are stored within a std::vector\ (you could also use a Mat of type CV_32SC1). Think of + the label as the subject (the person) this image belongs to, so same subjects (persons) should have + the same label. For the available FaceRecognizer you don't have to pay any attention to the order of + the labels, just make sure same persons have the same label: + + @code + // holds images and labels + vector images; + vector labels; + // images for first person + images.push_back(imread("person0/0.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(0); + images.push_back(imread("person0/1.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(0); + images.push_back(imread("person0/2.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(0); + // images for second person + images.push_back(imread("person1/0.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(1); + images.push_back(imread("person1/1.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(1); + images.push_back(imread("person1/2.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(1); + @endcode + + Now that you have read some images, we can create a new FaceRecognizer. In this example I'll create + a Fisherfaces model and decide to keep all of the possible Fisherfaces: + + @code + // Create a new Fisherfaces model and retain all available Fisherfaces, + // this is the most common usage of this specific FaceRecognizer: + // + Ptr model = createFisherFaceRecognizer(); + @endcode + + And finally train it on the given dataset (the face images and labels): + + @code + // This is the common interface to train all of the available cv::FaceRecognizer + // implementations: + // + model->train(images, labels); + @endcode + */ + CV_WRAP virtual void train(InputArrayOfArrays src, InputArray labels) = 0; + + /** @brief Updates a FaceRecognizer with given data and associated labels. + + @param src The training images, that means the faces you want to learn. The data has to be given + as a vector\. + @param labels The labels corresponding to the images have to be given either as a vector\ or + a + + This method updates a (probably trained) FaceRecognizer, but only if the algorithm supports it. The + Local Binary Patterns Histograms (LBPH) recognizer (see createLBPHFaceRecognizer) can be updated. + For the Eigenfaces and Fisherfaces method, this is algorithmically not possible and you have to + re-estimate the model with FaceRecognizer::train. In any case, a call to train empties the existing + model and learns a new model, while update does not delete any model data. + + @code + // Create a new LBPH model (it can be updated) and use the default parameters, + // this is the most common usage of this specific FaceRecognizer: + // + Ptr model = createLBPHFaceRecognizer(); + // This is the common interface to train all of the available cv::FaceRecognizer + // implementations: + // + model->train(images, labels); + // Some containers to hold new image: + vector newImages; + vector newLabels; + // You should add some images to the containers: + // + // ... + // + // Now updating the model is as easy as calling: + model->update(newImages,newLabels); + // This will preserve the old model data and extend the existing model + // with the new features extracted from newImages! + @endcode + + Calling update on an Eigenfaces model (see createEigenFaceRecognizer), which doesn't support + updating, will throw an error similar to: + + @code + OpenCV Error: The function/feature is not implemented (This FaceRecognizer (FaceRecognizer.Eigenfaces) does not support updating, you have to use FaceRecognizer::train to update it.) in update, file /home/philipp/git/opencv/modules/contrib/src/facerec.cpp, line 305 + terminate called after throwing an instance of 'cv::Exception' + @endcode + + @note The FaceRecognizer does not store your training images, because this would be very + memory intense and it's not the responsibility of te FaceRecognizer to do so. The caller is + responsible for maintaining the dataset, he want to work with. + */ + CV_WRAP virtual void update(InputArrayOfArrays src, InputArray labels); + + /** @overload */ + virtual int predict(InputArray src) const = 0; + + /** @brief Predicts a label and associated confidence (e.g. distance) for a given input image. + + @param src Sample image to get a prediction from. + @param label The predicted label for the given image. + @param confidence Associated confidence (e.g. distance) for the predicted label. + + The suffix const means that prediction does not affect the internal model state, so the method can + be safely called from within different threads. + + The following example shows how to get a prediction from a trained model: + + @code + using namespace cv; + // Do your initialization here (create the cv::FaceRecognizer model) ... + // ... + // Read in a sample image: + Mat img = imread("person1/3.jpg", CV_LOAD_IMAGE_GRAYSCALE); + // And get a prediction from the cv::FaceRecognizer: + int predicted = model->predict(img); + @endcode + + Or to get a prediction and the associated confidence (e.g. distance): + + @code + using namespace cv; + // Do your initialization here (create the cv::FaceRecognizer model) ... + // ... + Mat img = imread("person1/3.jpg", CV_LOAD_IMAGE_GRAYSCALE); + // Some variables for the predicted label and associated confidence (e.g. distance): + int predicted_label = -1; + double predicted_confidence = 0.0; + // Get the prediction and associated confidence from the model + model->predict(img, predicted_label, predicted_confidence); + @endcode + */ + CV_WRAP virtual void predict(InputArray src, CV_OUT int &label, CV_OUT double &confidence) const = 0; + + /** @brief Saves a FaceRecognizer and its model state. + + Saves this model to a given filename, either as XML or YAML. + @param filename The filename to store this FaceRecognizer to (either XML/YAML). + + Every FaceRecognizer overwrites FaceRecognizer::save(FileStorage& fs) to save the internal model + state. FaceRecognizer::save(const String& filename) saves the state of a model to the given + filename. + + The suffix const means that prediction does not affect the internal model state, so the method can + be safely called from within different threads. + */ + CV_WRAP virtual void save(const String& filename) const; + + /** @brief Loads a FaceRecognizer and its model state. + + Loads a persisted model and state from a given XML or YAML file . Every FaceRecognizer has to + overwrite FaceRecognizer::load(FileStorage& fs) to enable loading the model state. + FaceRecognizer::load(FileStorage& fs) in turn gets called by + FaceRecognizer::load(const String& filename), to ease saving a model. + */ + CV_WRAP virtual void load(const String& filename); + + /** @overload + Saves this model to a given FileStorage. + @param fs The FileStorage to store this FaceRecognizer to. + */ + virtual void save(FileStorage& fs) const = 0; + + /** @overload */ + virtual void load(const FileStorage& fs) = 0; + + /** @brief Sets string info for the specified model's label. + + The string info is replaced by the provided value if it was set before for the specified label. + */ + CV_WRAP virtual void setLabelInfo(int label, const String& strInfo); + + /** @brief Gets string information by label. + + If an unknown label id is provided or there is no label information associated with the specified + label id the method returns an empty string. + */ + CV_WRAP virtual String getLabelInfo(int label) const; + + /** @brief Gets vector of labels by string. + + The function searches for the labels containing the specified sub-string in the associated string + info. + */ + CV_WRAP virtual std::vector getLabelsByString(const String& str) const; + +protected: + // Stored pairs "label id - string info" + std::map _labelsInfo; +}; + +//! @} + +}} + +#include "opencv2/face/facerec.hpp" + #endif diff --git a/modules/face/include/opencv2/face/facerec.hpp b/modules/face/include/opencv2/face/facerec.hpp index 49291b46c..ddb933997 100644 --- a/modules/face/include/opencv2/face/facerec.hpp +++ b/modules/face/include/opencv2/face/facerec.hpp @@ -8,6 +8,7 @@ #ifndef __OPENCV_FACEREC_HPP__ #define __OPENCV_FACEREC_HPP__ +#include "opencv2/face.hpp" #include "opencv2/core.hpp" namespace cv { namespace face { @@ -15,299 +16,17 @@ namespace cv { namespace face { //! @addtogroup face //! @{ -/** @brief Abstract base class for all face recognition models - -All face recognition models in OpenCV are derived from the abstract base class FaceRecognizer, which -provides a unified access to all face recongition algorithms in OpenCV. - -### Description - -I'll go a bit more into detail explaining FaceRecognizer, because it doesn't look like a powerful -interface at first sight. But: Every FaceRecognizer is an Algorithm, so you can easily get/set all -model internals (if allowed by the implementation). Algorithm is a relatively new OpenCV concept, -which is available since the 2.4 release. I suggest you take a look at its description. - -Algorithm provides the following features for all derived classes: - -- So called “virtual constructor”. That is, each Algorithm derivative is registered at program - start and you can get the list of registered algorithms and create instance of a particular - algorithm by its name (see Algorithm::create). If you plan to add your own algorithms, it is - good practice to add a unique prefix to your algorithms to distinguish them from other - algorithms. -- Setting/Retrieving algorithm parameters by name. If you used video capturing functionality from - OpenCV highgui module, you are probably familar with cv::cvSetCaptureProperty, -ocvcvGetCaptureProperty, VideoCapture::set and VideoCapture::get. Algorithm provides similar - method where instead of integer id's you specify the parameter names as text Strings. See - Algorithm::set and Algorithm::get for details. -- Reading and writing parameters from/to XML or YAML files. Every Algorithm derivative can store - all its parameters and then read them back. There is no need to re-implement it each time. - -Moreover every FaceRecognizer supports the: - -- **Training** of a FaceRecognizer with FaceRecognizer::train on a given set of images (your face - database!). -- **Prediction** of a given sample image, that means a face. The image is given as a Mat. -- **Loading/Saving** the model state from/to a given XML or YAML. -- **Setting/Getting labels info**, that is stored as a string. String labels info is useful for - keeping names of the recognized people. - -@note When using the FaceRecognizer interface in combination with Python, please stick to Python 2. -Some underlying scripts like create_csv will not work in other versions, like Python 3. Setting the -Thresholds +++++++++++++++++++++++ - -Sometimes you run into the situation, when you want to apply a threshold on the prediction. A common -scenario in face recognition is to tell, whether a face belongs to the training dataset or if it is -unknown. You might wonder, why there's no public API in FaceRecognizer to set the threshold for the -prediction, but rest assured: It's supported. It just means there's no generic way in an abstract -class to provide an interface for setting/getting the thresholds of *every possible* FaceRecognizer -algorithm. The appropriate place to set the thresholds is in the constructor of the specific -FaceRecognizer and since every FaceRecognizer is a Algorithm (see above), you can get/set the -thresholds at runtime! - -Here is an example of setting a threshold for the Eigenfaces method, when creating the model: - -@code -// Let's say we want to keep 10 Eigenfaces and have a threshold value of 10.0 -int num_components = 10; -double threshold = 10.0; -// Then if you want to have a cv::FaceRecognizer with a confidence threshold, -// create the concrete implementation with the appropiate parameters: -Ptr model = createEigenFaceRecognizer(num_components, threshold); -@endcode - -Sometimes it's impossible to train the model, just to experiment with threshold values. Thanks to -Algorithm it's possible to set internal model thresholds during runtime. Let's see how we would -set/get the prediction for the Eigenface model, we've created above: - -@code -// The following line reads the threshold from the Eigenfaces model: -double current_threshold = model->getDouble("threshold"); -// And this line sets the threshold to 0.0: -model->set("threshold", 0.0); -@endcode - -If you've set the threshold to 0.0 as we did above, then: - -@code -// -Mat img = imread("person1/3.jpg", CV_LOAD_IMAGE_GRAYSCALE); -// Get a prediction from the model. Note: We've set a threshold of 0.0 above, -// since the distance is almost always larger than 0.0, you'll get -1 as -// label, which indicates, this face is unknown -int predicted_label = model->predict(img); -// ... -@endcode - -is going to yield -1 as predicted label, which states this face is unknown. - -### Getting the name of a FaceRecognizer - -Since every FaceRecognizer is a Algorithm, you can use Algorithm::name to get the name of a -FaceRecognizer: - -@code -// Create a FaceRecognizer: -Ptr model = createEigenFaceRecognizer(); -// And here's how to get its name: -String name = model->name(); -@endcode - - */ -class CV_EXPORTS_W FaceRecognizer : public Algorithm +// base for two classes +class CV_EXPORTS_W BasicFaceRecognizer : public FaceRecognizer { public: - //! virtual destructor - virtual ~FaceRecognizer() {} - - /** @brief Trains a FaceRecognizer with given data and associated labels. - - @param src The training images, that means the faces you want to learn. The data has to be - given as a vector\. - @param labels The labels corresponding to the images have to be given either as a vector\ - or a - - The following source code snippet shows you how to learn a Fisherfaces model on a given set of - images. The images are read with imread and pushed into a std::vector\. The labels of each - image are stored within a std::vector\ (you could also use a Mat of type CV_32SC1). Think of - the label as the subject (the person) this image belongs to, so same subjects (persons) should have - the same label. For the available FaceRecognizer you don't have to pay any attention to the order of - the labels, just make sure same persons have the same label: - - @code - // holds images and labels - vector images; - vector labels; - // images for first person - images.push_back(imread("person0/0.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(0); - images.push_back(imread("person0/1.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(0); - images.push_back(imread("person0/2.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(0); - // images for second person - images.push_back(imread("person1/0.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(1); - images.push_back(imread("person1/1.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(1); - images.push_back(imread("person1/2.jpg", CV_LOAD_IMAGE_GRAYSCALE)); labels.push_back(1); - @endcode - - Now that you have read some images, we can create a new FaceRecognizer. In this example I'll create - a Fisherfaces model and decide to keep all of the possible Fisherfaces: - - @code - // Create a new Fisherfaces model and retain all available Fisherfaces, - // this is the most common usage of this specific FaceRecognizer: - // - Ptr model = createFisherFaceRecognizer(); - @endcode - - And finally train it on the given dataset (the face images and labels): - - @code - // This is the common interface to train all of the available cv::FaceRecognizer - // implementations: - // - model->train(images, labels); - @endcode - */ - CV_WRAP virtual void train(InputArrayOfArrays src, InputArray labels) = 0; - - /** @brief Updates a FaceRecognizer with given data and associated labels. - - @param src The training images, that means the faces you want to learn. The data has to be given - as a vector\. - @param labels The labels corresponding to the images have to be given either as a vector\ or - a - - This method updates a (probably trained) FaceRecognizer, but only if the algorithm supports it. The - Local Binary Patterns Histograms (LBPH) recognizer (see createLBPHFaceRecognizer) can be updated. - For the Eigenfaces and Fisherfaces method, this is algorithmically not possible and you have to - re-estimate the model with FaceRecognizer::train. In any case, a call to train empties the existing - model and learns a new model, while update does not delete any model data. - - @code - // Create a new LBPH model (it can be updated) and use the default parameters, - // this is the most common usage of this specific FaceRecognizer: - // - Ptr model = createLBPHFaceRecognizer(); - // This is the common interface to train all of the available cv::FaceRecognizer - // implementations: - // - model->train(images, labels); - // Some containers to hold new image: - vector newImages; - vector newLabels; - // You should add some images to the containers: - // - // ... - // - // Now updating the model is as easy as calling: - model->update(newImages,newLabels); - // This will preserve the old model data and extend the existing model - // with the new features extracted from newImages! - @endcode - - Calling update on an Eigenfaces model (see createEigenFaceRecognizer), which doesn't support - updating, will throw an error similar to: - - @code - OpenCV Error: The function/feature is not implemented (This FaceRecognizer (FaceRecognizer.Eigenfaces) does not support updating, you have to use FaceRecognizer::train to update it.) in update, file /home/philipp/git/opencv/modules/contrib/src/facerec.cpp, line 305 - terminate called after throwing an instance of 'cv::Exception' - @endcode - - @note The FaceRecognizer does not store your training images, because this would be very - memory intense and it's not the responsibility of te FaceRecognizer to do so. The caller is - responsible for maintaining the dataset, he want to work with. - */ - CV_WRAP virtual void update(InputArrayOfArrays src, InputArray labels) = 0; - - /** @overload */ - virtual int predict(InputArray src) const = 0; - - /** @brief Predicts a label and associated confidence (e.g. distance) for a given input image. - - @param src Sample image to get a prediction from. - @param label The predicted label for the given image. - @param confidence Associated confidence (e.g. distance) for the predicted label. - - The suffix const means that prediction does not affect the internal model state, so the method can - be safely called from within different threads. - - The following example shows how to get a prediction from a trained model: - - @code - using namespace cv; - // Do your initialization here (create the cv::FaceRecognizer model) ... - // ... - // Read in a sample image: - Mat img = imread("person1/3.jpg", CV_LOAD_IMAGE_GRAYSCALE); - // And get a prediction from the cv::FaceRecognizer: - int predicted = model->predict(img); - @endcode - - Or to get a prediction and the associated confidence (e.g. distance): - - @code - using namespace cv; - // Do your initialization here (create the cv::FaceRecognizer model) ... - // ... - Mat img = imread("person1/3.jpg", CV_LOAD_IMAGE_GRAYSCALE); - // Some variables for the predicted label and associated confidence (e.g. distance): - int predicted_label = -1; - double predicted_confidence = 0.0; - // Get the prediction and associated confidence from the model - model->predict(img, predicted_label, predicted_confidence); - @endcode - */ - CV_WRAP virtual void predict(InputArray src, CV_OUT int &label, CV_OUT double &confidence) const = 0; - - /** @brief Saves a FaceRecognizer and its model state. - - Saves this model to a given filename, either as XML or YAML. - @param filename The filename to store this FaceRecognizer to (either XML/YAML). - - Every FaceRecognizer overwrites FaceRecognizer::save(FileStorage& fs) to save the internal model - state. FaceRecognizer::save(const String& filename) saves the state of a model to the given - filename. - - The suffix const means that prediction does not affect the internal model state, so the method can - be safely called from within different threads. - */ - CV_WRAP virtual void save(const String& filename) const = 0; - - /** @brief Loads a FaceRecognizer and its model state. - - Loads a persisted model and state from a given XML or YAML file . Every FaceRecognizer has to - overwrite FaceRecognizer::load(FileStorage& fs) to enable loading the model state. - FaceRecognizer::load(FileStorage& fs) in turn gets called by - FaceRecognizer::load(const String& filename), to ease saving a model. - */ - CV_WRAP virtual void load(const String& filename) = 0; - - /** @overload - Saves this model to a given FileStorage. - @param fs The FileStorage to store this FaceRecognizer to. - */ - virtual void save(FileStorage& fs) const = 0; - - /** @overload */ - virtual void load(const FileStorage& fs) = 0; - - /** @brief Sets string info for the specified model's label. - - The string info is replaced by the provided value if it was set before for the specified label. - */ - virtual void setLabelInfo(int label, const String& strInfo) = 0; - - /** @brief Gets string information by label. - - If an unknown label id is provided or there is no label information associated with the specified - label id the method returns an empty string. - */ - virtual String getLabelInfo(int label) const = 0; - - /** @brief Gets vector of labels by string. - - The function searches for the labels containing the specified sub-string in the associated string - info. - */ - virtual std::vector getLabelsByString(const String& str) const = 0; + CV_PURE_PROPERTY(int, NumComponents) + CV_PURE_PROPERTY(double, Threshold) + CV_PURE_PROPERTY_RO(std::vector, Projections) + CV_PURE_PROPERTY_RO(cv::Mat, Labels) + CV_PURE_PROPERTY_RO(cv::Mat, EigenValues) + CV_PURE_PROPERTY_RO(cv::Mat, EigenVectors) + CV_PURE_PROPERTY_RO(cv::Mat, Mean) }; /** @@ -339,7 +58,8 @@ number. Keeping 80 components should almost always be sufficient. - 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 createEigenFaceRecognizer(int num_components = 0, double threshold = DBL_MAX); +CV_EXPORTS_W Ptr 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 @@ -370,7 +90,20 @@ is larger than the threshold, this method returns -1. - projections The projections of the training data. - labels The labels corresponding to the projections. */ -CV_EXPORTS_W Ptr createFisherFaceRecognizer(int num_components = 0, double threshold = DBL_MAX); +CV_EXPORTS_W Ptr createFisherFaceRecognizer(int num_components = 0, double threshold = DBL_MAX); + +class CV_EXPORTS_W LBPHFaceRecognizer : public FaceRecognizer +{ +public: + CV_PURE_PROPERTY(int, GridX) + CV_PURE_PROPERTY(int, GridY) + CV_PURE_PROPERTY(int, Radius) + CV_PURE_PROPERTY(int, Neighbors) + CV_PURE_PROPERTY(double, Threshold) + CV_PURE_PROPERTY_RO(std::vector, Histograms) + CV_PURE_PROPERTY_RO(cv::Mat, Labels) +}; + /** @param radius The radius used for building the Circular Local Binary Pattern. The greater the radius, the @@ -403,9 +136,7 @@ is larger than the threshold, this method returns -1. none was given). - labels Labels corresponding to the calculated Local Binary Patterns Histograms. */ -CV_EXPORTS_W Ptr createLBPHFaceRecognizer(int radius=1, int neighbors=8, int grid_x=8, int grid_y=8, double threshold = DBL_MAX); - -bool initModule_facerec(); +CV_EXPORTS_W Ptr createLBPHFaceRecognizer(int radius=1, int neighbors=8, int grid_x=8, int grid_y=8, double threshold = DBL_MAX); //! @} diff --git a/modules/face/samples/facerec_demo.cpp b/modules/face/samples/facerec_demo.cpp index ab9e7e568..26ad17757 100644 --- a/modules/face/samples/facerec_demo.cpp +++ b/modules/face/samples/facerec_demo.cpp @@ -128,7 +128,7 @@ int main(int argc, const char *argv[]) { // // cv::createEigenFaceRecognizer(10, 123.0); // - Ptr model = createEigenFaceRecognizer(); + Ptr model = createEigenFaceRecognizer(); for( int i = 0; i < nlabels; i++ ) model->setLabelInfo(i, labelsInfo[i]); model->train(images, labels); @@ -162,16 +162,16 @@ int main(int argc, const char *argv[]) { // to 0.0 without retraining the model. This can be useful if // you are evaluating the model: // - model->set("threshold", 0.0); + 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; // Here is how to get the eigenvalues of this Eigenfaces model: - Mat eigenvalues = model->getMat("eigenvalues"); + Mat eigenvalues = model->getEigenValues(); // And we can do the same to display the Eigenvectors (read Eigenfaces): - Mat W = model->getMat("eigenvectors"); + Mat W = model->getEigenVectors(); // From this we will display the (at most) first 10 Eigenfaces: for (int i = 0; i < min(10, W.cols); i++) { string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at(i)); diff --git a/modules/face/src/eigen_faces.cpp b/modules/face/src/eigen_faces.cpp new file mode 100644 index 000000000..8247ad79f --- /dev/null +++ b/modules/face/src/eigen_faces.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011,2012. Philipp Wagner . + * 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 + */ +#include "precomp.hpp" +#include "face_basic.hpp" +#include +#include +#include + +namespace cv +{ +namespace face +{ + +// Turk, M., and Pentland, A. "Eigenfaces for recognition.". Journal of +// Cognitive Neuroscience 3 (1991), 71–86. +class Eigenfaces : public BasicFaceRecognizerImpl +{ + +public: + // Initializes an empty Eigenfaces model. + Eigenfaces(int num_components = 0, double threshold = DBL_MAX) + : BasicFaceRecognizerImpl(num_components, threshold) + {} + + // Computes an Eigenfaces model with images in src and corresponding labels + // in labels. + void train(InputArrayOfArrays src, InputArray labels); + + // Predicts the label of a query image in src. + int predict(InputArray src) const; + + // Predicts the label and confidence for a given sample. + void predict(InputArray _src, int &label, double &dist) const; +}; + +//------------------------------------------------------------------------------ +// Eigenfaces +//------------------------------------------------------------------------------ +void Eigenfaces::train(InputArrayOfArrays _src, InputArray _local_labels) { + if(_src.total() == 0) { + String error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); + CV_Error(Error::StsBadArg, error_message); + } else if(_local_labels.getMat().type() != CV_32SC1) { + String error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _local_labels.type()); + CV_Error(Error::StsBadArg, error_message); + } + // make sure data has correct size + if(_src.total() > 1) { + for(int i = 1; i < static_cast(_src.total()); i++) { + if(_src.getMat(i-1).total() != _src.getMat(i).total()) { + 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()); + CV_Error(Error::StsUnsupportedFormat, error_message); + } + } + } + // get labels + Mat labels = _local_labels.getMat(); + // observations in row + Mat data = asRowMatrix(_src, CV_64FC1); + + // number of samples + int n = data.rows; + // assert there are as much samples as labels + if(static_cast(labels.total()) != n) { + 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()); + CV_Error(Error::StsBadArg, error_message); + } + // clear existing model data + _labels.release(); + _projections.clear(); + // clip number of components to be valid + if((_num_components <= 0) || (_num_components > n)) + _num_components = n; + + // perform the PCA + PCA pca(data, Mat(), PCA::DATA_AS_ROW, _num_components); + // copy the PCA results + _mean = pca.mean.reshape(1,1); // store the mean vector + _eigenvalues = pca.eigenvalues.clone(); // eigenvalues by row + transpose(pca.eigenvectors, _eigenvectors); // eigenvectors by column + // store labels for prediction + _labels = labels.clone(); + // save projections + for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) { + Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx)); + _projections.push_back(p); + } +} + +void Eigenfaces::predict(InputArray _src, int &minClass, double &minDist) const { + // get data + Mat src = _src.getMat(); + // make sure the user is passing correct data + if(_projections.empty()) { + // throw error if no data (or simply return -1?) + String error_message = "This Eigenfaces model is not computed yet. Did you call Eigenfaces::train?"; + CV_Error(Error::StsError, error_message); + } else if(_eigenvectors.rows != static_cast(src.total())) { + // check data alignment just for clearer exception messages + 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()); + CV_Error(Error::StsBadArg, error_message); + } + // project into PCA subspace + Mat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1,1)); + minDist = DBL_MAX; + minClass = -1; + for(size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) { + double dist = norm(_projections[sampleIdx], q, NORM_L2); + if((dist < minDist) && (dist < _threshold)) { + minDist = dist; + minClass = _labels.at((int)sampleIdx); + } + } +} + +int Eigenfaces::predict(InputArray _src) const { + int label; + double dummy; + predict(_src, label, dummy); + return label; +} + +Ptr createEigenFaceRecognizer(int num_components, double threshold) +{ + return makePtr(num_components, threshold); +} + +} +} diff --git a/modules/face/src/face_basic.hpp b/modules/face/src/face_basic.hpp new file mode 100644 index 000000000..ce9be823c --- /dev/null +++ b/modules/face/src/face_basic.hpp @@ -0,0 +1,175 @@ +#ifndef __OPENCV_FACE_BASIC_HPP +#define __OPENCV_FACE_BASIC_HPP + +#include "opencv2/face.hpp" +#include "precomp.hpp" + +#include +#include +#include + +using namespace cv; + +// Reads a sequence from a FileNode::SEQ with type _Tp into a result vector. +template +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 +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) { + // 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) { + String error_message = "The data is expected as InputArray::STD_VECTOR_MAT (a std::vector) or _InputArray::STD_VECTOR_VECTOR (a std::vector< std::vector<...> >)."; + CV_Error(Error::StsBadArg, error_message); + } + // number of samples + size_t n = src.total(); + // return empty matrix if no matrices given + if(n == 0) + return Mat(); + // dimensionality of (reshaped) samples + size_t d = src.getMat(0).total(); + // create data matrix + Mat data((int)n, (int)d, rtype); + // now copy data + for(unsigned int i = 0; i < n; i++) { + // make sure data can be reshaped, throw exception if not! + if(src.getMat(i).total() != d) { + String error_message = format("Wrong number of elements in matrix #%d! Expected %d was %d.", i, d, src.getMat(i).total()); + CV_Error(Error::StsBadArg, error_message); + } + // get a hold of the current row + Mat xi = data.row(i); + // make reshape happy by cloning for non-continuous matrices + if(src.getMat(i).isContinuous()) { + src.getMat(i).reshape(1, 1).convertTo(xi, rtype, alpha, beta); + } else { + src.getMat(i).clone().reshape(1, 1).convertTo(xi, rtype, alpha, beta); + } + } + return data; +} + +// Utility structure to load/save face label info (a pair of int and string) via FileStorage +struct LabelInfo +{ + LabelInfo():label(-1), value("") {} + LabelInfo(int _label, const String &_value): label(_label), value(_value) {} + int label; + String value; + void write(cv::FileStorage& fs) const + { + fs << "{" << "label" << label << "value" << value << "}"; + } + void read(const cv::FileNode& node) + { + label = (int)node["label"]; + value = (String)node["value"]; + } + std::ostream& operator<<(std::ostream& out) + { + out << "{ label = " << label << ", " << "value = " << value.c_str() << "}"; + return out; + } +}; + +inline void write(cv::FileStorage& fs, const String&, const LabelInfo& x) +{ + x.write(fs); +} + +inline void read(const cv::FileNode& node, LabelInfo& x, const LabelInfo& default_value = LabelInfo()) +{ + if(node.empty()) + x = default_value; + else + x.read(node); +} + + +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::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, 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 _projections; + Mat _labels; + Mat _eigenvectors; + Mat _eigenvalues; + Mat _mean; +}; + +#endif // __OPENCV_FACE_BASIC_HPP + diff --git a/modules/face/src/facerec.cpp b/modules/face/src/facerec.cpp index 497e8351d..dac7d082b 100644 --- a/modules/face/src/facerec.cpp +++ b/modules/face/src/facerec.cpp @@ -16,1009 +16,60 @@ * See */ #include "precomp.hpp" -#include -#include -#include +#include "opencv2/face.hpp" namespace cv { namespace face { -// Reads a sequence from a FileNode::SEQ with type _Tp into a result vector. -template -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 -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 << "]"; -} - -static 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 - if(src.kind() != _InputArray::STD_VECTOR_MAT && src.kind() != _InputArray::STD_VECTOR_VECTOR) { - String error_message = "The data is expected as InputArray::STD_VECTOR_MAT (a std::vector) or _InputArray::STD_VECTOR_VECTOR (a std::vector< std::vector<...> >)."; - CV_Error(Error::StsBadArg, error_message); - } - // number of samples - size_t n = src.total(); - // return empty matrix if no matrices given - if(n == 0) - return Mat(); - // dimensionality of (reshaped) samples - size_t d = src.getMat(0).total(); - // create data matrix - Mat data((int)n, (int)d, rtype); - // now copy data - for(unsigned int i = 0; i < n; i++) { - // make sure data can be reshaped, throw exception if not! - if(src.getMat(i).total() != d) { - String error_message = format("Wrong number of elements in matrix #%d! Expected %d was %d.", i, d, src.getMat(i).total()); - CV_Error(Error::StsBadArg, error_message); - } - // get a hold of the current row - Mat xi = data.row(i); - // make reshape happy by cloning for non-continuous matrices - if(src.getMat(i).isContinuous()) { - src.getMat(i).reshape(1, 1).convertTo(xi, rtype, alpha, beta); - } else { - src.getMat(i).clone().reshape(1, 1).convertTo(xi, rtype, alpha, beta); - } - } - return data; -} - - -// Removes duplicate elements in a given vector. -template -inline std::vector<_Tp> remove_dups(const std::vector<_Tp>& src) { - typedef typename std::set<_Tp>::const_iterator constSetIterator; - typedef typename std::vector<_Tp>::const_iterator constVecIterator; - std::set<_Tp> set_elems; - for (constVecIterator it = src.begin(); it != src.end(); ++it) - set_elems.insert(*it); - std::vector<_Tp> elems; - for (constSetIterator it = set_elems.begin(); it != set_elems.end(); ++it) - elems.push_back(*it); - return elems; -} - -class FaceRecognizerImpl : public FaceRecognizer -{ -public: - using FaceRecognizer::save; - using FaceRecognizer::load; - - // Serializes this object to a given filename. - virtual void save(const String& filename) const - { - FileStorage fs(filename, FileStorage::WRITE); - if (!fs.isOpened()) - CV_Error(Error::StsError, "File can't be opened for writing!"); - this->save(fs); - fs.release(); - } - - // Deserializes this object from a given filename. - virtual void load(const String& filename) - { - FileStorage fs(filename, FileStorage::READ); - if (!fs.isOpened()) - CV_Error(Error::StsError, "File can't be opened for writing!"); - this->load(fs); - fs.release(); - } - - // Updates a FaceRecognizer. - virtual void update(InputArrayOfArrays src, InputArray labels) - { - (void)src; - (void)labels; - String error_msg = format("This FaceRecognizer (%s) does not support updating, you have to use FaceRecognizer::train to update it.", this->name().c_str()); - CV_Error(Error::StsNotImplemented, error_msg); - } - - - // Sets additional string info for the label - virtual void setLabelInfo(int label, const String& strInfo) - { - _labelsInfo[label] = strInfo; - } - - // Gets string info by label - virtual String getLabelInfo(int label) const - { - std::map::const_iterator iter(_labelsInfo.find(label)); - return iter != _labelsInfo.end() ? iter->second : ""; - } - - // Gets labels by string - virtual std::vector getLabelsByString(const String& str) const - { - std::vector labels; - for (std::map::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++) - { - size_t found = (it->second).find(str); - if (found != String::npos) - labels.push_back(it->first); - } - return labels; - } - -protected: - // Stored pairs "label id - string info" - std::map _labelsInfo; -}; - - - -// Utility structure to load/save face label info (a pair of int and string) via FileStorage -struct LabelInfo -{ - LabelInfo():label(-1), value("") {} - LabelInfo(int _label, const String &_value): label(_label), value(_value) {} - int label; - String value; - void write(cv::FileStorage& fs) const - { - fs << "{" << "label" << label << "value" << value << "}"; - } - void read(const cv::FileNode& node) - { - label = (int)node["label"]; - value = (String)node["value"]; - } - std::ostream& operator<<(std::ostream& out) - { - out << "{ label = " << label << ", " << "value = " << value.c_str() << "}"; - return out; - } -}; - -static void write(cv::FileStorage& fs, const String&, const LabelInfo& x) -{ - x.write(fs); -} - -static void read(const cv::FileNode& node, LabelInfo& x, const LabelInfo& default_value = LabelInfo()) -{ - if(node.empty()) - x = default_value; - else - x.read(node); -} - - - -// Turk, M., and Pentland, A. "Eigenfaces for recognition.". Journal of -// Cognitive Neuroscience 3 (1991), 71–86. -class Eigenfaces : public FaceRecognizerImpl -{ -private: - int _num_components; - double _threshold; - std::vector _projections; - Mat _labels; - Mat _eigenvectors; - Mat _eigenvalues; - Mat _mean; - -public: - using FaceRecognizer::save; - using FaceRecognizer::load; - - // Initializes an empty Eigenfaces model. - Eigenfaces(int num_components = 0, double threshold = DBL_MAX) : - _num_components(num_components), - _threshold(threshold) {} - - // Initializes and computes an Eigenfaces model with images in src and - // corresponding labels in labels. num_components will be kept for - // classification. - Eigenfaces(InputArrayOfArrays src, InputArray labels, - int num_components = 0, double threshold = DBL_MAX) : - _num_components(num_components), - _threshold(threshold) { - train(src, labels); - } - - // Computes an Eigenfaces model with images in src and corresponding labels - // in labels. - void train(InputArrayOfArrays src, InputArray labels); - - // Predicts the label of a query image in src. - int predict(InputArray src) const; - - // Predicts the label and confidence for a given sample. - void predict(InputArray _src, int &label, double &dist) const; - - // See FaceRecognizer::load. - void load(const FileStorage& fs); - - // See FaceRecognizer::save. - void save(FileStorage& fs) const; - - AlgorithmInfo* info() const; -}; - -// Belhumeur, P. N., Hespanha, J., and Kriegman, D. "Eigenfaces vs. Fisher- -// faces: Recognition using class specific linear projection.". IEEE -// Transactions on Pattern Analysis and Machine Intelligence 19, 7 (1997), -// 711–720. -class Fisherfaces: public FaceRecognizerImpl -{ -private: - int _num_components; - double _threshold; - Mat _eigenvectors; - Mat _eigenvalues; - Mat _mean; - std::vector _projections; - Mat _labels; - -public: - using FaceRecognizer::save; - using FaceRecognizer::load; - - // Initializes an empty Fisherfaces model. - Fisherfaces(int num_components = 0, double threshold = DBL_MAX) : - _num_components(num_components), - _threshold(threshold) {} - - // Initializes and computes a Fisherfaces model with images in src and - // corresponding labels in labels. num_components will be kept for - // classification. - Fisherfaces(InputArrayOfArrays src, InputArray labels, - int num_components = 0, double threshold = DBL_MAX) : - _num_components(num_components), - _threshold(threshold) { - train(src, labels); - } - - ~Fisherfaces() {} - - // Computes a Fisherfaces model with images in src and corresponding labels - // in labels. - void train(InputArrayOfArrays src, InputArray labels); - - // Predicts the label of a query image in src. - int predict(InputArray src) const; - - // Predicts the label and confidence for a given sample. - void predict(InputArray _src, int &label, double &dist) const; - - // See FaceRecognizer::load. - void load(const FileStorage& fs); - - // See FaceRecognizer::save. - void save(FileStorage& fs) const; - - AlgorithmInfo* info() const; -}; - -// Face Recognition based on Local Binary Patterns. -// -// Ahonen T, Hadid A. and Pietikäinen M. "Face description with local binary -// patterns: Application to face recognition." IEEE Transactions on Pattern -// Analysis and Machine Intelligence, 28(12):2037-2041. -// -class LBPH : public FaceRecognizerImpl -{ -private: - int _grid_x; - int _grid_y; - int _radius; - int _neighbors; - double _threshold; - - std::vector _histograms; - Mat _labels; - - // Computes a LBPH model with images in src and - // corresponding labels in labels, possibly preserving - // old model data. - void train(InputArrayOfArrays src, InputArray labels, bool preserveData); - - -public: - using FaceRecognizer::save; - using FaceRecognizer::load; - - // Initializes this LBPH Model. The current implementation is rather fixed - // as it uses the Extended Local Binary Patterns per default. - // - // radius, neighbors are used in the local binary patterns creation. - // grid_x, grid_y control the grid size of the spatial histograms. - LBPH(int radius_=1, int neighbors_=8, - int gridx=8, int gridy=8, - double threshold = DBL_MAX) : - _grid_x(gridx), - _grid_y(gridy), - _radius(radius_), - _neighbors(neighbors_), - _threshold(threshold) {} - - // Initializes and computes this LBPH Model. The current implementation is - // rather fixed as it uses the Extended Local Binary Patterns per default. - // - // (radius=1), (neighbors=8) are used in the local binary patterns creation. - // (grid_x=8), (grid_y=8) controls the grid size of the spatial histograms. - LBPH(InputArrayOfArrays src, - InputArray labels, - int radius_=1, int neighbors_=8, - int gridx=8, int gridy=8, - double threshold = DBL_MAX) : - _grid_x(gridx), - _grid_y(gridy), - _radius(radius_), - _neighbors(neighbors_), - _threshold(threshold) { - train(src, labels); - } - - ~LBPH() { } - - // Computes a LBPH model with images in src and - // corresponding labels in labels. - void train(InputArrayOfArrays src, InputArray labels); - - // Updates this LBPH model with images in src and - // corresponding labels in labels. - void update(InputArrayOfArrays src, InputArray labels); - - // Predicts the label of a query image in src. - int predict(InputArray src) const; - - // Predicts the label and confidence for a given sample. - void predict(InputArray _src, int &label, double &dist) const; - - // See FaceRecognizer::load. - void load(const FileStorage& fs); - - // See FaceRecognizer::save. - void save(FileStorage& fs) const; - - // Getter functions. - int neighbors() const { return _neighbors; } - int radius() const { return _radius; } - int grid_x() const { return _grid_x; } - int grid_y() const { return _grid_y; } - - AlgorithmInfo* info() const; -}; - - -//------------------------------------------------------------------------------ -// Eigenfaces -//------------------------------------------------------------------------------ -void Eigenfaces::train(InputArrayOfArrays _src, InputArray _local_labels) { - if(_src.total() == 0) { - String error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); - CV_Error(Error::StsBadArg, error_message); - } else if(_local_labels.getMat().type() != CV_32SC1) { - String error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _local_labels.type()); - CV_Error(Error::StsBadArg, error_message); - } - // make sure data has correct size - if(_src.total() > 1) { - for(int i = 1; i < static_cast(_src.total()); i++) { - if(_src.getMat(i-1).total() != _src.getMat(i).total()) { - 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()); - CV_Error(Error::StsUnsupportedFormat, error_message); - } - } - } - // get labels - Mat labels = _local_labels.getMat(); - // observations in row - Mat data = asRowMatrix(_src, CV_64FC1); - - // number of samples - int n = data.rows; - // assert there are as much samples as labels - if(static_cast(labels.total()) != n) { - 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()); - CV_Error(Error::StsBadArg, error_message); - } - // clear existing model data - _labels.release(); - _projections.clear(); - // clip number of components to be valid - if((_num_components <= 0) || (_num_components > n)) - _num_components = n; - - // perform the PCA - PCA pca(data, Mat(), PCA::DATA_AS_ROW, _num_components); - // copy the PCA results - _mean = pca.mean.reshape(1,1); // store the mean vector - _eigenvalues = pca.eigenvalues.clone(); // eigenvalues by row - transpose(pca.eigenvectors, _eigenvectors); // eigenvectors by column - // store labels for prediction - _labels = labels.clone(); - // save projections - for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) { - Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx)); - _projections.push_back(p); - } -} - -void Eigenfaces::predict(InputArray _src, int &minClass, double &minDist) const { - // get data - Mat src = _src.getMat(); - // make sure the user is passing correct data - if(_projections.empty()) { - // throw error if no data (or simply return -1?) - String error_message = "This Eigenfaces model is not computed yet. Did you call Eigenfaces::train?"; - CV_Error(Error::StsError, error_message); - } else if(_eigenvectors.rows != static_cast(src.total())) { - // check data alignment just for clearer exception messages - 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()); - CV_Error(Error::StsBadArg, error_message); - } - // project into PCA subspace - Mat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1,1)); - minDist = DBL_MAX; - minClass = -1; - for(size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) { - double dist = norm(_projections[sampleIdx], q, NORM_L2); - if((dist < minDist) && (dist < _threshold)) { - minDist = dist; - minClass = _labels.at((int)sampleIdx); - } - } -} - -int Eigenfaces::predict(InputArray _src) const { - int label; - double dummy; - predict(_src, label, dummy); - return label; -} - -void Eigenfaces::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 Eigenfaces::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::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++) - fs << LabelInfo(it->first, it->second); - fs << "]"; -} - -//------------------------------------------------------------------------------ -// Fisherfaces -//------------------------------------------------------------------------------ -void Fisherfaces::train(InputArrayOfArrays src, InputArray _lbls) { - if(src.total() == 0) { - String error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); - CV_Error(Error::StsBadArg, error_message); - } else if(_lbls.getMat().type() != CV_32SC1) { - String error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _lbls.type()); - CV_Error(Error::StsBadArg, error_message); - } - // make sure data has correct size - if(src.total() > 1) { - for(int i = 1; i < static_cast(src.total()); i++) { - if(src.getMat(i-1).total() != src.getMat(i).total()) { - 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()); - CV_Error(Error::StsUnsupportedFormat, error_message); - } - } - } - // get data - Mat labels = _lbls.getMat(); - Mat data = asRowMatrix(src, CV_64FC1); - // number of samples - int N = data.rows; - // make sure labels are passed in correct shape - if(labels.total() != (size_t) N) { - 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()); - CV_Error(Error::StsBadArg, error_message); - } else if(labels.rows != 1 && labels.cols != 1) { - 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); - CV_Error(Error::StsBadArg, error_message); - } - // clear existing model data - _labels.release(); - _projections.clear(); - // safely copy from cv::Mat to std::vector - std::vector ll; - for(unsigned int i = 0; i < labels.total(); i++) { - ll.push_back(labels.at(i)); - } - // get the number of unique classes - int C = (int) remove_dups(ll).size(); - // clip number of components to be a valid number - if((_num_components <= 0) || (_num_components > (C-1))) - _num_components = (C-1); - // perform a PCA and keep (N-C) components - PCA pca(data, Mat(), PCA::DATA_AS_ROW, (N-C)); - // project the data and perform a LDA on it - LDA lda(pca.project(data),labels, _num_components); - // store the total mean vector - _mean = pca.mean.reshape(1,1); - // store labels - _labels = labels.clone(); - // store the eigenvalues of the discriminants - lda.eigenvalues().convertTo(_eigenvalues, CV_64FC1); - // Now calculate the projection matrix as pca.eigenvectors * lda.eigenvectors. - // Note: OpenCV stores the eigenvectors by row, so we need to transpose it! - gemm(pca.eigenvectors, lda.eigenvectors(), 1.0, Mat(), 0.0, _eigenvectors, GEMM_1_T); - // store the projections of the original data - for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) { - Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx)); - _projections.push_back(p); - } -} - -void Fisherfaces::predict(InputArray _src, int &minClass, double &minDist) const { - Mat src = _src.getMat(); - // check data alignment just for clearer exception messages - if(_projections.empty()) { - // throw error if no data (or simply return -1?) - String error_message = "This Fisherfaces model is not computed yet. Did you call Fisherfaces::train?"; - CV_Error(Error::StsBadArg, error_message); - } else if(src.total() != (size_t) _eigenvectors.rows) { - 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()); - CV_Error(Error::StsBadArg, error_message); - } - // project into LDA subspace - Mat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1,1)); - // find 1-nearest neighbor - minDist = DBL_MAX; - minClass = -1; - for(size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) { - double dist = norm(_projections[sampleIdx], q, NORM_L2); - if((dist < minDist) && (dist < _threshold)) { - minDist = dist; - minClass = _labels.at((int)sampleIdx); - } - } -} - -int Fisherfaces::predict(InputArray _src) const { - int label; - double dummy; - predict(_src, label, dummy); - return label; -} - -// See FaceRecognizer::load. -void Fisherfaces::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)); - } - } -} - -// See FaceRecognizer::save. -void Fisherfaces::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::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++) - fs << LabelInfo(it->first, it->second); - fs << "]"; -} - -//------------------------------------------------------------------------------ -// LBPH -//------------------------------------------------------------------------------ - -template static -void olbp_(InputArray _src, OutputArray _dst) { - // get matrices - Mat src = _src.getMat(); - // allocate memory for result - _dst.create(src.rows-2, src.cols-2, CV_8UC1); - Mat dst = _dst.getMat(); - // zero the result matrix - dst.setTo(0); - // calculate patterns - for(int i=1;i(i,j); - unsigned char code = 0; - code |= (src.at<_Tp>(i-1,j-1) >= center) << 7; - code |= (src.at<_Tp>(i-1,j) >= center) << 6; - code |= (src.at<_Tp>(i-1,j+1) >= center) << 5; - code |= (src.at<_Tp>(i,j+1) >= center) << 4; - code |= (src.at<_Tp>(i+1,j+1) >= center) << 3; - code |= (src.at<_Tp>(i+1,j) >= center) << 2; - code |= (src.at<_Tp>(i+1,j-1) >= center) << 1; - code |= (src.at<_Tp>(i,j-1) >= center) << 0; - dst.at(i-1,j-1) = code; - } - } -} - -//------------------------------------------------------------------------------ -// cv::elbp -//------------------------------------------------------------------------------ -template static -inline void elbp_(InputArray _src, OutputArray _dst, int radius, int neighbors) { - //get matrices - Mat src = _src.getMat(); - // allocate memory for result - _dst.create(src.rows-2*radius, src.cols-2*radius, CV_32SC1); - Mat dst = _dst.getMat(); - // zero - dst.setTo(0); - for(int n=0; n(radius * cos(2.0*CV_PI*n/static_cast(neighbors))); - float y = static_cast(-radius * sin(2.0*CV_PI*n/static_cast(neighbors))); - // relative indices - int fx = static_cast(floor(x)); - int fy = static_cast(floor(y)); - int cx = static_cast(ceil(x)); - int cy = static_cast(ceil(y)); - // fractional part - float ty = y - fy; - float tx = x - fx; - // set interpolation weights - float w1 = (1 - tx) * (1 - ty); - float w2 = tx * (1 - ty); - float w3 = (1 - tx) * ty; - float w4 = tx * ty; - // iterate through your data - for(int i=radius; i < src.rows-radius;i++) { - for(int j=radius;j < src.cols-radius;j++) { - // calculate interpolated value - float t = static_cast(w1*src.at<_Tp>(i+fy,j+fx) + w2*src.at<_Tp>(i+fy,j+cx) + w3*src.at<_Tp>(i+cy,j+fx) + w4*src.at<_Tp>(i+cy,j+cx)); - // floating point precision, so check some machine-dependent epsilon - dst.at(i-radius,j-radius) += ((t > src.at<_Tp>(i,j)) || (std::abs(t-src.at<_Tp>(i,j)) < std::numeric_limits::epsilon())) << n; - } - } - } -} - -static void elbp(InputArray src, OutputArray dst, int radius, int neighbors) -{ - int type = src.type(); - switch (type) { - case CV_8SC1: elbp_(src,dst, radius, neighbors); break; - case CV_8UC1: elbp_(src, dst, radius, neighbors); break; - case CV_16SC1: elbp_(src,dst, radius, neighbors); break; - case CV_16UC1: elbp_(src,dst, radius, neighbors); break; - case CV_32SC1: elbp_(src,dst, radius, neighbors); break; - case CV_32FC1: elbp_(src,dst, radius, neighbors); break; - case CV_64FC1: elbp_(src,dst, radius, neighbors); break; - default: - String error_msg = format("Using Original Local Binary Patterns for feature extraction only works on single-channel images (given %d). Please pass the image data as a grayscale image!", type); - CV_Error(Error::StsNotImplemented, error_msg); - break; - } -} - -static Mat -histc_(const Mat& src, int minVal=0, int maxVal=255, bool normed=false) -{ - Mat result; - // Establish the number of bins. - int histSize = maxVal-minVal+1; - // Set the ranges. - float range[] = { static_cast(minVal), static_cast(maxVal+1) }; - const float* histRange = { range }; - // calc histogram - calcHist(&src, 1, 0, Mat(), result, 1, &histSize, &histRange, true, false); - // normalize - if(normed) { - result /= (int)src.total(); - } - return result.reshape(1,1); -} - -static Mat histc(InputArray _src, int minVal, int maxVal, bool normed) +std::vector FaceRecognizer::getLabelsByString(const String &str) const { - Mat src = _src.getMat(); - switch (src.type()) { - case CV_8SC1: - return histc_(Mat_(src), minVal, maxVal, normed); - break; - case CV_8UC1: - return histc_(src, minVal, maxVal, normed); - break; - case CV_16SC1: - return histc_(Mat_(src), minVal, maxVal, normed); - break; - case CV_16UC1: - return histc_(src, minVal, maxVal, normed); - break; - case CV_32SC1: - return histc_(Mat_(src), minVal, maxVal, normed); - break; - case CV_32FC1: - return histc_(src, minVal, maxVal, normed); - break; - default: - CV_Error(Error::StsUnmatchedFormats, "This type is not implemented yet."); break; - } - return Mat(); + std::vector labels; + for (std::map::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++) + { + size_t found = (it->second).find(str); + if (found != String::npos) + labels.push_back(it->first); + } + return labels; } - -static Mat spatial_histogram(InputArray _src, int numPatterns, - int grid_x, int grid_y, bool /*normed*/) +String FaceRecognizer::getLabelInfo(int label) const { - Mat src = _src.getMat(); - // calculate LBP patch size - int width = src.cols/grid_x; - int height = src.rows/grid_y; - // allocate memory for the spatial histogram - Mat result = Mat::zeros(grid_x * grid_y, numPatterns, CV_32FC1); - // return matrix with zeros if no data was given - if(src.empty()) - return result.reshape(1,1); - // initial result_row - int resultRowIdx = 0; - // iterate through grid - for(int i = 0; i < grid_y; i++) { - for(int j = 0; j < grid_x; j++) { - Mat src_cell = Mat(src, Range(i*height,(i+1)*height), Range(j*width,(j+1)*width)); - Mat cell_hist = histc(src_cell, 0, (numPatterns-1), true); - // copy to the result matrix - Mat result_row = result.row(resultRowIdx); - cell_hist.reshape(1,1).convertTo(result_row, CV_32FC1); - // increase row count in result matrix - resultRowIdx++; - } - } - // return result as reshaped feature vector - return result.reshape(1,1); -} - -//------------------------------------------------------------------------------ -// wrapper to cv::elbp (extended local binary patterns) -//------------------------------------------------------------------------------ - -static Mat elbp(InputArray src, int radius, int neighbors) { - Mat dst; - elbp(src, dst, radius, neighbors); - return dst; -} - -void LBPH::load(const FileStorage& fs) { - fs["radius"] >> _radius; - fs["neighbors"] >> _neighbors; - fs["grid_x"] >> _grid_x; - fs["grid_y"] >> _grid_y; - //read matrices - readFileNodeList(fs["histograms"], _histograms); - 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)); - } - } -} - -// See FaceRecognizer::save. -void LBPH::save(FileStorage& fs) const { - fs << "radius" << _radius; - fs << "neighbors" << _neighbors; - fs << "grid_x" << _grid_x; - fs << "grid_y" << _grid_y; - // write matrices - writeFileNodeList(fs, "histograms", _histograms); - fs << "labels" << _labels; - fs << "labelsInfo" << "["; - for (std::map::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++) - fs << LabelInfo(it->first, it->second); - fs << "]"; -} - -void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels) { - this->train(_in_src, _in_labels, false); -} - -void LBPH::update(InputArrayOfArrays _in_src, InputArray _in_labels) { - // got no data, just return - if(_in_src.total() == 0) - return; - - this->train(_in_src, _in_labels, true); -} - -void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels, bool preserveData) { - if(_in_src.kind() != _InputArray::STD_VECTOR_MAT && _in_src.kind() != _InputArray::STD_VECTOR_VECTOR) { - String error_message = "The images are expected as InputArray::STD_VECTOR_MAT (a std::vector) or _InputArray::STD_VECTOR_VECTOR (a std::vector< std::vector<...> >)."; - CV_Error(Error::StsBadArg, error_message); - } - if(_in_src.total() == 0) { - String error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); - CV_Error(Error::StsUnsupportedFormat, error_message); - } else if(_in_labels.getMat().type() != CV_32SC1) { - String error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _in_labels.type()); - CV_Error(Error::StsUnsupportedFormat, error_message); - } - // get the vector of matrices - std::vector src; - _in_src.getMatVector(src); - // get the label matrix - Mat labels = _in_labels.getMat(); - // check if data is well- aligned - if(labels.total() != src.size()) { - String error_message = format("The number of samples (src) must equal the number of labels (labels). Was len(samples)=%d, len(labels)=%d.", src.size(), _labels.total()); - CV_Error(Error::StsBadArg, error_message); - } - // if this model should be trained without preserving old data, delete old model data - if(!preserveData) { - _labels.release(); - _histograms.clear(); - } - // append labels to _labels matrix - for(size_t labelIdx = 0; labelIdx < labels.total(); labelIdx++) { - _labels.push_back(labels.at((int)labelIdx)); - } - // store the spatial histograms of the original data - for(size_t sampleIdx = 0; sampleIdx < src.size(); sampleIdx++) { - // calculate lbp image - Mat lbp_image = elbp(src[sampleIdx], _radius, _neighbors); - // get spatial histogram from this lbp image - Mat p = spatial_histogram( - lbp_image, /* lbp_image */ - static_cast(std::pow(2.0, static_cast(_neighbors))), /* number of possible patterns */ - _grid_x, /* grid size x */ - _grid_y, /* grid size y */ - true); - // add to templates - _histograms.push_back(p); - } + std::map::const_iterator iter(_labelsInfo.find(label)); + return iter != _labelsInfo.end() ? iter->second : ""; } -void LBPH::predict(InputArray _src, int &minClass, double &minDist) const { - if(_histograms.empty()) { - // throw error if no data (or simply return -1?) - String error_message = "This LBPH model is not computed yet. Did you call the train method?"; - CV_Error(Error::StsBadArg, error_message); - } - Mat src = _src.getMat(); - // get the spatial histogram from input image - Mat lbp_image = elbp(src, _radius, _neighbors); - Mat query = spatial_histogram( - lbp_image, /* lbp_image */ - static_cast(std::pow(2.0, static_cast(_neighbors))), /* number of possible patterns */ - _grid_x, /* grid size x */ - _grid_y, /* grid size y */ - true /* normed histograms */); - // find 1-nearest neighbor - minDist = DBL_MAX; - minClass = -1; - for(size_t sampleIdx = 0; sampleIdx < _histograms.size(); sampleIdx++) { - double dist = compareHist(_histograms[sampleIdx], query, HISTCMP_CHISQR_ALT); - if((dist < minDist) && (dist < _threshold)) { - minDist = dist; - minClass = _labels.at((int) sampleIdx); - } - } -} - -int LBPH::predict(InputArray _src) const { - int label; - double dummy; - predict(_src, label, dummy); - return label; -} - - -Ptr createEigenFaceRecognizer(int num_components, double threshold) +void FaceRecognizer::setLabelInfo(int label, const String &strInfo) { - return makePtr(num_components, threshold); + _labelsInfo[label] = strInfo; } -Ptr createFisherFaceRecognizer(int num_components, double threshold) +void FaceRecognizer::update(InputArrayOfArrays src, InputArray labels) { - return makePtr(num_components, threshold); + (void)src; + (void)labels; + String error_msg = format("This FaceRecognizer does not support updating, you have to use FaceRecognizer::train to update it."); + CV_Error(Error::StsNotImplemented, error_msg); } -Ptr createLBPHFaceRecognizer(int radius, int neighbors, - int grid_x, int grid_y, double threshold) +void FaceRecognizer::load(const String &filename) { - return makePtr(radius, neighbors, grid_x, grid_y, threshold); + FileStorage fs(filename, FileStorage::READ); + if (!fs.isOpened()) + CV_Error(Error::StsError, "File can't be opened for writing!"); + this->load(fs); + fs.release(); } -CV_INIT_ALGORITHM(Eigenfaces, "FaceRecognizer.Eigenfaces", - obj.info()->addParam(obj, "ncomponents", obj._num_components); - obj.info()->addParam(obj, "threshold", obj._threshold); - 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, "threshold", obj._threshold); - 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, "threshold", obj._threshold); - obj.info()->addParam(obj, "histograms", obj._histograms, true); - obj.info()->addParam(obj, "labels", obj._labels, true)) - -bool initModule_facerec() +void FaceRecognizer::save(const String &filename) const { - return !Eigenfaces_info_auto.name().empty() && !Fisherfaces_info_auto.name().empty() && !LBPH_info_auto.name().empty(); + FileStorage fs(filename, FileStorage::WRITE); + if (!fs.isOpened()) + CV_Error(Error::StsError, "File can't be opened for writing!"); + this->save(fs); + fs.release(); } } diff --git a/modules/face/src/fisher_faces.cpp b/modules/face/src/fisher_faces.cpp new file mode 100644 index 000000000..d8466f996 --- /dev/null +++ b/modules/face/src/fisher_faces.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2011,2012. Philipp Wagner . + * 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 + */ +#include "precomp.hpp" +#include "face_basic.hpp" + +namespace cv { namespace face { + +// Belhumeur, P. N., Hespanha, J., and Kriegman, D. "Eigenfaces vs. Fisher- +// faces: Recognition using class specific linear projection.". IEEE +// Transactions on Pattern Analysis and Machine Intelligence 19, 7 (1997), +// 711–720. +class Fisherfaces: public BasicFaceRecognizerImpl +{ +public: + // Initializes an empty Fisherfaces model. + Fisherfaces(int num_components = 0, double threshold = DBL_MAX) + : BasicFaceRecognizerImpl(num_components, threshold) + { } + + // Computes a Fisherfaces model with images in src and corresponding labels + // in labels. + void train(InputArrayOfArrays src, InputArray labels); + + // Predicts the label of a query image in src. + int predict(InputArray src) const; + + // Predicts the label and confidence for a given sample. + void predict(InputArray _src, int &label, double &dist) const; +}; + +// Removes duplicate elements in a given vector. +template +inline std::vector<_Tp> remove_dups(const std::vector<_Tp>& src) { + typedef typename std::set<_Tp>::const_iterator constSetIterator; + typedef typename std::vector<_Tp>::const_iterator constVecIterator; + std::set<_Tp> set_elems; + for (constVecIterator it = src.begin(); it != src.end(); ++it) + set_elems.insert(*it); + std::vector<_Tp> elems; + for (constSetIterator it = set_elems.begin(); it != set_elems.end(); ++it) + elems.push_back(*it); + return elems; +} + +//------------------------------------------------------------------------------ +// Fisherfaces +//------------------------------------------------------------------------------ +void Fisherfaces::train(InputArrayOfArrays src, InputArray _lbls) { + if(src.total() == 0) { + String error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); + CV_Error(Error::StsBadArg, error_message); + } else if(_lbls.getMat().type() != CV_32SC1) { + String error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _lbls.type()); + CV_Error(Error::StsBadArg, error_message); + } + // make sure data has correct size + if(src.total() > 1) { + for(int i = 1; i < static_cast(src.total()); i++) { + if(src.getMat(i-1).total() != src.getMat(i).total()) { + 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()); + CV_Error(Error::StsUnsupportedFormat, error_message); + } + } + } + // get data + Mat labels = _lbls.getMat(); + Mat data = asRowMatrix(src, CV_64FC1); + // number of samples + int N = data.rows; + // make sure labels are passed in correct shape + if(labels.total() != (size_t) N) { + 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()); + CV_Error(Error::StsBadArg, error_message); + } else if(labels.rows != 1 && labels.cols != 1) { + 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); + CV_Error(Error::StsBadArg, error_message); + } + // clear existing model data + _labels.release(); + _projections.clear(); + // safely copy from cv::Mat to std::vector + std::vector ll; + for(unsigned int i = 0; i < labels.total(); i++) { + ll.push_back(labels.at(i)); + } + // get the number of unique classes + int C = (int) remove_dups(ll).size(); + // clip number of components to be a valid number + if((_num_components <= 0) || (_num_components > (C-1))) + _num_components = (C-1); + // perform a PCA and keep (N-C) components + PCA pca(data, Mat(), PCA::DATA_AS_ROW, (N-C)); + // project the data and perform a LDA on it + LDA lda(pca.project(data),labels, _num_components); + // store the total mean vector + _mean = pca.mean.reshape(1,1); + // store labels + _labels = labels.clone(); + // store the eigenvalues of the discriminants + lda.eigenvalues().convertTo(_eigenvalues, CV_64FC1); + // Now calculate the projection matrix as pca.eigenvectors * lda.eigenvectors. + // Note: OpenCV stores the eigenvectors by row, so we need to transpose it! + gemm(pca.eigenvectors, lda.eigenvectors(), 1.0, Mat(), 0.0, _eigenvectors, GEMM_1_T); + // store the projections of the original data + for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) { + Mat p = LDA::subspaceProject(_eigenvectors, _mean, data.row(sampleIdx)); + _projections.push_back(p); + } +} + +void Fisherfaces::predict(InputArray _src, int &minClass, double &minDist) const { + Mat src = _src.getMat(); + // check data alignment just for clearer exception messages + if(_projections.empty()) { + // throw error if no data (or simply return -1?) + String error_message = "This Fisherfaces model is not computed yet. Did you call Fisherfaces::train?"; + CV_Error(Error::StsBadArg, error_message); + } else if(src.total() != (size_t) _eigenvectors.rows) { + 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()); + CV_Error(Error::StsBadArg, error_message); + } + // project into LDA subspace + Mat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1,1)); + // find 1-nearest neighbor + minDist = DBL_MAX; + minClass = -1; + for(size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) { + double dist = norm(_projections[sampleIdx], q, NORM_L2); + if((dist < minDist) && (dist < _threshold)) { + minDist = dist; + minClass = _labels.at((int)sampleIdx); + } + } +} + +int Fisherfaces::predict(InputArray _src) const { + int label; + double dummy; + predict(_src, label, dummy); + return label; +} + +Ptr createFisherFaceRecognizer(int num_components, double threshold) +{ + return makePtr(num_components, threshold); +} + +} } diff --git a/modules/face/src/lbph_faces.cpp b/modules/face/src/lbph_faces.cpp new file mode 100644 index 000000000..bc01acefb --- /dev/null +++ b/modules/face/src/lbph_faces.cpp @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2011,2012. Philipp Wagner . + * 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 + */ +#include "precomp.hpp" +#include "opencv2/face.hpp" +#include "face_basic.hpp" + +namespace cv { namespace face { + +// Face Recognition based on Local Binary Patterns. +// +// Ahonen T, Hadid A. and Pietikäinen M. "Face description with local binary +// patterns: Application to face recognition." IEEE Transactions on Pattern +// Analysis and Machine Intelligence, 28(12):2037-2041. +// +class LBPH : public LBPHFaceRecognizer +{ +private: + int _grid_x; + int _grid_y; + int _radius; + int _neighbors; + double _threshold; + + std::vector _histograms; + Mat _labels; + + // Computes a LBPH model with images in src and + // corresponding labels in labels, possibly preserving + // old model data. + void train(InputArrayOfArrays src, InputArray labels, bool preserveData); + + +public: + using FaceRecognizer::save; + using FaceRecognizer::load; + + // Initializes this LBPH Model. The current implementation is rather fixed + // as it uses the Extended Local Binary Patterns per default. + // + // radius, neighbors are used in the local binary patterns creation. + // grid_x, grid_y control the grid size of the spatial histograms. + LBPH(int radius_=1, int neighbors_=8, + int gridx=8, int gridy=8, + double threshold = DBL_MAX) : + _grid_x(gridx), + _grid_y(gridy), + _radius(radius_), + _neighbors(neighbors_), + _threshold(threshold) {} + + // Initializes and computes this LBPH Model. The current implementation is + // rather fixed as it uses the Extended Local Binary Patterns per default. + // + // (radius=1), (neighbors=8) are used in the local binary patterns creation. + // (grid_x=8), (grid_y=8) controls the grid size of the spatial histograms. + LBPH(InputArrayOfArrays src, + InputArray labels, + int radius_=1, int neighbors_=8, + int gridx=8, int gridy=8, + double threshold = DBL_MAX) : + _grid_x(gridx), + _grid_y(gridy), + _radius(radius_), + _neighbors(neighbors_), + _threshold(threshold) { + train(src, labels); + } + + ~LBPH() { } + + // Computes a LBPH model with images in src and + // corresponding labels in labels. + void train(InputArrayOfArrays src, InputArray labels); + + // Updates this LBPH model with images in src and + // corresponding labels in labels. + void update(InputArrayOfArrays src, InputArray labels); + + // Predicts the label of a query image in src. + int predict(InputArray src) const; + + // Predicts the label and confidence for a given sample. + void predict(InputArray _src, int &label, double &dist) const; + + // See FaceRecognizer::load. + void load(const FileStorage& fs); + + // See FaceRecognizer::save. + void save(FileStorage& fs) const; + + CV_IMPL_PROPERTY(int, GridX, _grid_x) + CV_IMPL_PROPERTY(int, GridY, _grid_y) + CV_IMPL_PROPERTY(int, Radius, _radius) + CV_IMPL_PROPERTY(int, Neighbors, _neighbors) + CV_IMPL_PROPERTY(double, Threshold, _threshold) + CV_IMPL_PROPERTY_RO(std::vector, Histograms, _histograms) + CV_IMPL_PROPERTY_RO(cv::Mat, Labels, _labels) +}; + + +void LBPH::load(const FileStorage& fs) { + fs["radius"] >> _radius; + fs["neighbors"] >> _neighbors; + fs["grid_x"] >> _grid_x; + fs["grid_y"] >> _grid_y; + //read matrices + readFileNodeList(fs["histograms"], _histograms); + 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)); + } + } +} + +// See FaceRecognizer::save. +void LBPH::save(FileStorage& fs) const { + fs << "radius" << _radius; + fs << "neighbors" << _neighbors; + fs << "grid_x" << _grid_x; + fs << "grid_y" << _grid_y; + // write matrices + writeFileNodeList(fs, "histograms", _histograms); + fs << "labels" << _labels; + fs << "labelsInfo" << "["; + for (std::map::const_iterator it = _labelsInfo.begin(); it != _labelsInfo.end(); it++) + fs << LabelInfo(it->first, it->second); + fs << "]"; +} + +void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels) { + this->train(_in_src, _in_labels, false); +} + +void LBPH::update(InputArrayOfArrays _in_src, InputArray _in_labels) { + // got no data, just return + if(_in_src.total() == 0) + return; + + this->train(_in_src, _in_labels, true); +} + + +//------------------------------------------------------------------------------ +// LBPH +//------------------------------------------------------------------------------ + +template static +void olbp_(InputArray _src, OutputArray _dst) { + // get matrices + Mat src = _src.getMat(); + // allocate memory for result + _dst.create(src.rows-2, src.cols-2, CV_8UC1); + Mat dst = _dst.getMat(); + // zero the result matrix + dst.setTo(0); + // calculate patterns + for(int i=1;i(i,j); + unsigned char code = 0; + code |= (src.at<_Tp>(i-1,j-1) >= center) << 7; + code |= (src.at<_Tp>(i-1,j) >= center) << 6; + code |= (src.at<_Tp>(i-1,j+1) >= center) << 5; + code |= (src.at<_Tp>(i,j+1) >= center) << 4; + code |= (src.at<_Tp>(i+1,j+1) >= center) << 3; + code |= (src.at<_Tp>(i+1,j) >= center) << 2; + code |= (src.at<_Tp>(i+1,j-1) >= center) << 1; + code |= (src.at<_Tp>(i,j-1) >= center) << 0; + dst.at(i-1,j-1) = code; + } + } +} + +//------------------------------------------------------------------------------ +// cv::elbp +//------------------------------------------------------------------------------ +template static +inline void elbp_(InputArray _src, OutputArray _dst, int radius, int neighbors) { + //get matrices + Mat src = _src.getMat(); + // allocate memory for result + _dst.create(src.rows-2*radius, src.cols-2*radius, CV_32SC1); + Mat dst = _dst.getMat(); + // zero + dst.setTo(0); + for(int n=0; n(radius * cos(2.0*CV_PI*n/static_cast(neighbors))); + float y = static_cast(-radius * sin(2.0*CV_PI*n/static_cast(neighbors))); + // relative indices + int fx = static_cast(floor(x)); + int fy = static_cast(floor(y)); + int cx = static_cast(ceil(x)); + int cy = static_cast(ceil(y)); + // fractional part + float ty = y - fy; + float tx = x - fx; + // set interpolation weights + float w1 = (1 - tx) * (1 - ty); + float w2 = tx * (1 - ty); + float w3 = (1 - tx) * ty; + float w4 = tx * ty; + // iterate through your data + for(int i=radius; i < src.rows-radius;i++) { + for(int j=radius;j < src.cols-radius;j++) { + // calculate interpolated value + float t = static_cast(w1*src.at<_Tp>(i+fy,j+fx) + w2*src.at<_Tp>(i+fy,j+cx) + w3*src.at<_Tp>(i+cy,j+fx) + w4*src.at<_Tp>(i+cy,j+cx)); + // floating point precision, so check some machine-dependent epsilon + dst.at(i-radius,j-radius) += ((t > src.at<_Tp>(i,j)) || (std::abs(t-src.at<_Tp>(i,j)) < std::numeric_limits::epsilon())) << n; + } + } + } +} + +static void elbp(InputArray src, OutputArray dst, int radius, int neighbors) +{ + int type = src.type(); + switch (type) { + case CV_8SC1: elbp_(src,dst, radius, neighbors); break; + case CV_8UC1: elbp_(src, dst, radius, neighbors); break; + case CV_16SC1: elbp_(src,dst, radius, neighbors); break; + case CV_16UC1: elbp_(src,dst, radius, neighbors); break; + case CV_32SC1: elbp_(src,dst, radius, neighbors); break; + case CV_32FC1: elbp_(src,dst, radius, neighbors); break; + case CV_64FC1: elbp_(src,dst, radius, neighbors); break; + default: + String error_msg = format("Using Original Local Binary Patterns for feature extraction only works on single-channel images (given %d). Please pass the image data as a grayscale image!", type); + CV_Error(Error::StsNotImplemented, error_msg); + break; + } +} + +static Mat +histc_(const Mat& src, int minVal=0, int maxVal=255, bool normed=false) +{ + Mat result; + // Establish the number of bins. + int histSize = maxVal-minVal+1; + // Set the ranges. + float range[] = { static_cast(minVal), static_cast(maxVal+1) }; + const float* histRange = { range }; + // calc histogram + calcHist(&src, 1, 0, Mat(), result, 1, &histSize, &histRange, true, false); + // normalize + if(normed) { + result /= (int)src.total(); + } + return result.reshape(1,1); +} + +static Mat histc(InputArray _src, int minVal, int maxVal, bool normed) +{ + Mat src = _src.getMat(); + switch (src.type()) { + case CV_8SC1: + return histc_(Mat_(src), minVal, maxVal, normed); + break; + case CV_8UC1: + return histc_(src, minVal, maxVal, normed); + break; + case CV_16SC1: + return histc_(Mat_(src), minVal, maxVal, normed); + break; + case CV_16UC1: + return histc_(src, minVal, maxVal, normed); + break; + case CV_32SC1: + return histc_(Mat_(src), minVal, maxVal, normed); + break; + case CV_32FC1: + return histc_(src, minVal, maxVal, normed); + break; + default: + CV_Error(Error::StsUnmatchedFormats, "This type is not implemented yet."); break; + } + return Mat(); +} + + +static Mat spatial_histogram(InputArray _src, int numPatterns, + int grid_x, int grid_y, bool /*normed*/) +{ + Mat src = _src.getMat(); + // calculate LBP patch size + int width = src.cols/grid_x; + int height = src.rows/grid_y; + // allocate memory for the spatial histogram + Mat result = Mat::zeros(grid_x * grid_y, numPatterns, CV_32FC1); + // return matrix with zeros if no data was given + if(src.empty()) + return result.reshape(1,1); + // initial result_row + int resultRowIdx = 0; + // iterate through grid + for(int i = 0; i < grid_y; i++) { + for(int j = 0; j < grid_x; j++) { + Mat src_cell = Mat(src, Range(i*height,(i+1)*height), Range(j*width,(j+1)*width)); + Mat cell_hist = histc(src_cell, 0, (numPatterns-1), true); + // copy to the result matrix + Mat result_row = result.row(resultRowIdx); + cell_hist.reshape(1,1).convertTo(result_row, CV_32FC1); + // increase row count in result matrix + resultRowIdx++; + } + } + // return result as reshaped feature vector + return result.reshape(1,1); +} + +//------------------------------------------------------------------------------ +// wrapper to cv::elbp (extended local binary patterns) +//------------------------------------------------------------------------------ + +static Mat elbp(InputArray src, int radius, int neighbors) { + Mat dst; + elbp(src, dst, radius, neighbors); + return dst; +} + +void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels, bool preserveData) { + if(_in_src.kind() != _InputArray::STD_VECTOR_MAT && _in_src.kind() != _InputArray::STD_VECTOR_VECTOR) { + String error_message = "The images are expected as InputArray::STD_VECTOR_MAT (a std::vector) or _InputArray::STD_VECTOR_VECTOR (a std::vector< std::vector<...> >)."; + CV_Error(Error::StsBadArg, error_message); + } + if(_in_src.total() == 0) { + String error_message = format("Empty training data was given. You'll need more than one sample to learn a model."); + CV_Error(Error::StsUnsupportedFormat, error_message); + } else if(_in_labels.getMat().type() != CV_32SC1) { + String error_message = format("Labels must be given as integer (CV_32SC1). Expected %d, but was %d.", CV_32SC1, _in_labels.type()); + CV_Error(Error::StsUnsupportedFormat, error_message); + } + // get the vector of matrices + std::vector src; + _in_src.getMatVector(src); + // get the label matrix + Mat labels = _in_labels.getMat(); + // check if data is well- aligned + if(labels.total() != src.size()) { + String error_message = format("The number of samples (src) must equal the number of labels (labels). Was len(samples)=%d, len(labels)=%d.", src.size(), _labels.total()); + CV_Error(Error::StsBadArg, error_message); + } + // if this model should be trained without preserving old data, delete old model data + if(!preserveData) { + _labels.release(); + _histograms.clear(); + } + // append labels to _labels matrix + for(size_t labelIdx = 0; labelIdx < labels.total(); labelIdx++) { + _labels.push_back(labels.at((int)labelIdx)); + } + // store the spatial histograms of the original data + for(size_t sampleIdx = 0; sampleIdx < src.size(); sampleIdx++) { + // calculate lbp image + Mat lbp_image = elbp(src[sampleIdx], _radius, _neighbors); + // get spatial histogram from this lbp image + Mat p = spatial_histogram( + lbp_image, /* lbp_image */ + static_cast(std::pow(2.0, static_cast(_neighbors))), /* number of possible patterns */ + _grid_x, /* grid size x */ + _grid_y, /* grid size y */ + true); + // add to templates + _histograms.push_back(p); + } +} + +void LBPH::predict(InputArray _src, int &minClass, double &minDist) const { + if(_histograms.empty()) { + // throw error if no data (or simply return -1?) + String error_message = "This LBPH model is not computed yet. Did you call the train method?"; + CV_Error(Error::StsBadArg, error_message); + } + Mat src = _src.getMat(); + // get the spatial histogram from input image + Mat lbp_image = elbp(src, _radius, _neighbors); + Mat query = spatial_histogram( + lbp_image, /* lbp_image */ + static_cast(std::pow(2.0, static_cast(_neighbors))), /* number of possible patterns */ + _grid_x, /* grid size x */ + _grid_y, /* grid size y */ + true /* normed histograms */); + // find 1-nearest neighbor + minDist = DBL_MAX; + minClass = -1; + for(size_t sampleIdx = 0; sampleIdx < _histograms.size(); sampleIdx++) { + double dist = compareHist(_histograms[sampleIdx], query, HISTCMP_CHISQR_ALT); + if((dist < minDist) && (dist < _threshold)) { + minDist = dist; + minClass = _labels.at((int) sampleIdx); + } + } +} + +int LBPH::predict(InputArray _src) const { + int label; + double dummy; + predict(_src, label, dummy); + return label; +} + +Ptr createLBPHFaceRecognizer(int radius, int neighbors, + int grid_x, int grid_y, double threshold) +{ + return makePtr(radius, neighbors, grid_x, grid_y, threshold); +} + + +}} diff --git a/modules/face/src/precomp.hpp b/modules/face/src/precomp.hpp index 883088da5..cde365d85 100644 --- a/modules/face/src/precomp.hpp +++ b/modules/face/src/precomp.hpp @@ -43,12 +43,16 @@ #ifndef __OPENCV_PRECOMP_H__ #define __OPENCV_PRECOMP_H__ -#include "opencv2/face.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/core.hpp" #include "opencv2/core/utility.hpp" #include "opencv2/core/private.hpp" - +#include "opencv2/core/persistence.hpp" #include +#include +#include +#include +#include #endif + diff --git a/modules/line_descriptor/include/opencv2/line_descriptor.hpp b/modules/line_descriptor/include/opencv2/line_descriptor.hpp index d01d1d577..171d29f0c 100644 --- a/modules/line_descriptor/include/opencv2/line_descriptor.hpp +++ b/modules/line_descriptor/include/opencv2/line_descriptor.hpp @@ -116,10 +116,4 @@ generates an 8 bit string. Concatenating 32 comparison strings, we get the 256-b representation of a single LBD. */ -namespace cv -{ -CV_EXPORTS bool initModule_line_descriptor( void ); - -} - #endif diff --git a/modules/line_descriptor/include/opencv2/line_descriptor/descriptor.hpp b/modules/line_descriptor/include/opencv2/line_descriptor/descriptor.hpp index 263af06ea..426b04d16 100644 --- a/modules/line_descriptor/include/opencv2/line_descriptor/descriptor.hpp +++ b/modules/line_descriptor/include/opencv2/line_descriptor/descriptor.hpp @@ -74,8 +74,6 @@ namespace line_descriptor //! @addtogroup line_descriptor //! @{ -CV_EXPORTS bool initModule_line_descriptor(); - /** @brief A class to represent a line As aformentioned, it is been necessary to design a class that fully stores the information needed to @@ -307,9 +305,6 @@ class CV_EXPORTS BinaryDescriptor : public Algorithm virtual void computeImpl( const Mat& imageSrc, std::vector& keylines, Mat& descriptors, bool returnFloatDescr, bool useDetectionData ) const; - /** function inherited from Algorithm */ - AlgorithmInfo* info() const; - private: /** struct to represent lines extracted from an octave */ struct OctaveLine @@ -911,10 +906,6 @@ void detectImpl( const Mat& imageSrc, std::vector& keylines, int numOct /* matrices for Gaussian pyramids */ std::vector gaussianPyrs; - -protected: -/* function inherited from Algorithm */ -AlgorithmInfo* info() const; }; /** @brief furnishes all functionalities for querying a dataset provided by user or internal to @@ -1068,10 +1059,6 @@ BinaryDescriptorMatcher(); { } -protected: -/** function inherited from Algorithm */ -AlgorithmInfo* info() const; - private: class BucketGroup { diff --git a/modules/line_descriptor/src/line_descriptor_init.cpp b/modules/line_descriptor/src/line_descriptor_init.cpp deleted file mode 100644 index afa6a3cfc..000000000 --- a/modules/line_descriptor/src/line_descriptor_init.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// - // - // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. - // - // By downloading, copying, installing or using the software you agree to this license. - // If you do not agree to this license, do not download, install, - // copy or use the software. - // - // - // License Agreement - // For Open Source Computer Vision Library - // - // Copyright (C) 2014, Biagio Montesano, all rights reserved. - // Third party copyrights are property of their respective owners. - // - // Redistribution and use in source and binary forms, with or without modification, - // are permitted provided that the following conditions are met: - // - // * Redistribution's of source code must retain the above copyright notice, - // this list of conditions and the following disclaimer. - // - // * Redistribution's 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. - // - // * The name of the copyright holders may not be used to endorse or promote products - // derived from this software without specific prior written permission. - // - // This software is provided by the copyright holders and contributors "as is" and - // any express or implied warranties, including, but not limited to, the implied - // warranties of merchantability and fitness for a particular purpose are disclaimed. - // In no event shall the Intel Corporation or contributors be liable for any direct, - // indirect, incidental, special, exemplary, or consequential damages - // (including, but not limited to, procurement of substitute goods or services; - // loss of use, data, or profits; or business interruption) however caused - // and on any theory of liability, whether in contract, strict liability, - // or tort (including negligence or otherwise) arising in any way out of - // the use of this software, even if advised of the possibility of such damage. - // - //M*/ - -#include "precomp.hpp" - -namespace cv -{ -namespace line_descriptor -{ - -CV_INIT_ALGORITHM( BinaryDescriptor, "BINARY.DESCRIPTOR", ); -CV_INIT_ALGORITHM( BinaryDescriptorMatcher, "BINARY.DESCRIPTOR.MATCHER", ); -CV_INIT_ALGORITHM( LSDDetector, "LSDDETECTOR", ); - -bool initModule_line_descriptor( void ) -{ - bool all = true; - all &= !BinaryDescriptor_info_auto.name().empty(); - all &= !BinaryDescriptorMatcher_info_auto.name().empty(); - all &= !LSDDetector_info_auto.name().empty(); - - return all; -} - -} -} diff --git a/modules/optflow/src/deepflow.cpp b/modules/optflow/src/deepflow.cpp index 334b1d2b9..9e2fa3a63 100644 --- a/modules/optflow/src/deepflow.cpp +++ b/modules/optflow/src/deepflow.cpp @@ -56,8 +56,6 @@ public: void calc( InputArray I0, InputArray I1, InputOutputArray flow ); void collectGarbage(); -// AlgorithmInfo* info() const; - protected: float sigma; // Gaussian smoothing parameter int minSize; // minimal dimension of an image in the pyramid diff --git a/modules/optflow/src/interfaces.cpp b/modules/optflow/src/interfaces.cpp index f11f54ed0..df510ebc3 100644 --- a/modules/optflow/src/interfaces.cpp +++ b/modules/optflow/src/interfaces.cpp @@ -56,7 +56,6 @@ public: OpticalFlowSimpleFlow(); void calc(InputArray I0, InputArray I1, InputOutputArray flow); void collectGarbage(); -// AlgorithmInfo* info() const; protected: int layers; @@ -129,7 +128,6 @@ public: OpticalFlowFarneback(); void calc(InputArray I0, InputArray I1, InputOutputArray flow); void collectGarbage(); -// AlgorithmInfo* info() const; protected: int numLevels; double pyrScale; diff --git a/modules/rgbd/include/opencv2/rgbd.hpp b/modules/rgbd/include/opencv2/rgbd.hpp index 9edd23953..9684bb1c1 100644 --- a/modules/rgbd/include/opencv2/rgbd.hpp +++ b/modules/rgbd/include/opencv2/rgbd.hpp @@ -137,9 +137,6 @@ namespace rgbd ~RgbdNormals(); - AlgorithmInfo* - info() const; - /** Given a set of 3d points in a depth image, compute the normals at each point. * @param points a rows x cols x 3 matrix of CV_32F/CV64F or a rows x cols x 1 CV_U16S * @param normals a rows x cols x 3 matrix @@ -153,14 +150,13 @@ namespace rgbd void initialize() const; - /** Return the current method in that normal computer - * @return - */ - int - method() const - { - return method_; - } + CV_IMPL_PROPERTY(int, Rows, rows_) + CV_IMPL_PROPERTY(int, Cols, cols_) + CV_IMPL_PROPERTY(int, WindowSize, window_size_) + CV_IMPL_PROPERTY(int, Depth, depth_) + CV_IMPL_PROPERTY_S(cv::Mat, K, K_) + CV_IMPL_PROPERTY(int, Method, method_) + protected: void initialize_normals_impl(int rows, int cols, int depth, const Mat & K, int window_size, int method) const; @@ -204,9 +200,6 @@ namespace rgbd ~DepthCleaner(); - AlgorithmInfo* - info() const; - /** Given a set of 3d points in a depth image, compute the normals at each point. * @param points a rows x cols x 3 matrix of CV_32F/CV64F or a rows x cols x 1 CV_U16S * @param depth a rows x cols matrix of the cleaned up depth @@ -220,14 +213,10 @@ namespace rgbd void initialize() const; - /** Return the current method in that normal computer - * @return - */ - int - method() const - { - return method_; - } + CV_IMPL_PROPERTY(int, WindowSize, window_size_) + CV_IMPL_PROPERTY(int, Depth, depth_) + CV_IMPL_PROPERTY(int, Method, method_) + protected: void initialize_cleaner_impl() const; @@ -316,8 +305,14 @@ namespace rgbd void operator()(InputArray points3d, OutputArray mask, OutputArray plane_coefficients); - AlgorithmInfo* - info() const; + CV_IMPL_PROPERTY(int, BlockSize, block_size_) + CV_IMPL_PROPERTY(int, MinSize, min_size_) + CV_IMPL_PROPERTY(int, Method, method_) + CV_IMPL_PROPERTY(double, Threshold, threshold_) + CV_IMPL_PROPERTY(double, SensorErrorA, sensor_error_a_) + CV_IMPL_PROPERTY(double, SensorErrorB, sensor_error_b_) + CV_IMPL_PROPERTY(double, SensorErrorC, sensor_error_c_) + private: /** The method to use to compute the planes */ int method_; @@ -469,6 +464,19 @@ namespace rgbd */ virtual Size prepareFrameCache(Ptr& frame, int cacheType) const; + static Ptr create(const String & odometryType); + + //TODO: which properties are common for all Odometry successors? + CV_PURE_PROPERTY_S(cv::Mat, CameraMatrix) +// CV_PURE_PROPERTY(double, MinDepth) +// CV_PURE_PROPERTY(double, MaxDepth) +// CV_PURE_PROPERTY(double, MaxDepthDiff) +// CV_PURE_PROPERTY_S(cv::Mat, IterationCounts) +// CV_PURE_PROPERTY(double, MaxPointsPart) + CV_PURE_PROPERTY(int, TransformType) +// CV_PURE_PROPERTY(double, MaxTranslation) +// CV_PURE_PROPERTY(double, MaxRotation) + protected: virtual void checkParams() const = 0; @@ -504,8 +512,16 @@ namespace rgbd virtual Size prepareFrameCache(Ptr& frame, int cacheType) const; - AlgorithmInfo* - info() const; + CV_IMPL_PROPERTY_S(cv::Mat, CameraMatrix, cameraMatrix) + CV_IMPL_PROPERTY(double, MinDepth, minDepth) + CV_IMPL_PROPERTY(double, MaxDepth, maxDepth) + CV_IMPL_PROPERTY(double, MaxDepthDiff, maxDepthDiff) + CV_IMPL_PROPERTY_S(cv::Mat, IterationCounts, iterCounts) + CV_IMPL_PROPERTY_S(cv::Mat, MinGradientMagnitudes, minGradientMagnitudes) + CV_IMPL_PROPERTY(double, MaxPointsPart, maxPointsPart) + CV_IMPL_PROPERTY(int, TransformType, transformType) + CV_IMPL_PROPERTY(double, MaxTranslation, maxTranslation) + CV_IMPL_PROPERTY(double, MaxRotation, maxRotation) protected: virtual void @@ -553,8 +569,16 @@ namespace rgbd virtual Size prepareFrameCache(Ptr& frame, int cacheType) const; - AlgorithmInfo* - info() const; + CV_IMPL_PROPERTY_S(cv::Mat, CameraMatrix, cameraMatrix) + CV_IMPL_PROPERTY(double, MinDepth, minDepth) + CV_IMPL_PROPERTY(double, MaxDepth, maxDepth) + CV_IMPL_PROPERTY(double, MaxDepthDiff, maxDepthDiff) + CV_IMPL_PROPERTY_S(cv::Mat, IterationCounts, iterCounts) + CV_IMPL_PROPERTY(double, MaxPointsPart, maxPointsPart) + CV_IMPL_PROPERTY(int, TransformType, transformType) + CV_IMPL_PROPERTY(double, MaxTranslation, maxTranslation) + CV_IMPL_PROPERTY(double, MaxRotation, maxRotation) + CV_IMPL_PROPERTY_RO(Ptr, NormalsComputer, normalsComputer) protected: virtual void @@ -607,8 +631,17 @@ namespace rgbd virtual Size prepareFrameCache(Ptr& frame, int cacheType) const; - AlgorithmInfo* - info() const; + CV_IMPL_PROPERTY_S(cv::Mat, CameraMatrix, cameraMatrix) + CV_IMPL_PROPERTY(double, MinDepth, minDepth) + CV_IMPL_PROPERTY(double, MaxDepth, maxDepth) + CV_IMPL_PROPERTY(double, MaxDepthDiff, maxDepthDiff) + CV_IMPL_PROPERTY(double, MaxPointsPart, maxPointsPart) + CV_IMPL_PROPERTY_S(cv::Mat, IterationCounts, iterCounts) + CV_IMPL_PROPERTY_S(cv::Mat, MinGradientMagnitudes, minGradientMagnitudes) + CV_IMPL_PROPERTY(int, TransformType, transformType) + CV_IMPL_PROPERTY(double, MaxTranslation, maxTranslation) + CV_IMPL_PROPERTY(double, MaxRotation, maxRotation) + CV_IMPL_PROPERTY_RO(Ptr, NormalsComputer, normalsComputer) protected: virtual void @@ -669,3 +702,4 @@ namespace rgbd #endif /* End of file. */ + diff --git a/modules/rgbd/samples/odometry_evaluation.cpp b/modules/rgbd/samples/odometry_evaluation.cpp index 07dbb2acd..b52c9287a 100644 --- a/modules/rgbd/samples/odometry_evaluation.cpp +++ b/modules/rgbd/samples/odometry_evaluation.cpp @@ -173,13 +173,13 @@ int main(int argc, char** argv) Ptr frame_prev = Ptr(new OdometryFrame()), frame_curr = Ptr(new OdometryFrame()); - Ptr odometry = Algorithm::create("RGBD." + string(argv[3]) + "Odometry"); + Ptr odometry = Odometry::create("RGBD." + string(argv[3]) + "Odometry"); if(odometry.empty()) { cout << "Can not create Odometry algorithm. Check the passed odometry name." << endl; return -1; } - odometry->set("cameraMatrix", cameraMatrix); + odometry->setCameraMatrix(cameraMatrix); MyTickMeter gtm; int count = 0; diff --git a/modules/rgbd/src/odometry.cpp b/modules/rgbd/src/odometry.cpp index 4d763d152..17b3dd3d4 100644 --- a/modules/rgbd/src/odometry.cpp +++ b/modules/rgbd/src/odometry.cpp @@ -1069,6 +1069,17 @@ Size Odometry::prepareFrameCache(Ptr &frame, int /*cacheType*/) c return Size(); } +Ptr Odometry::create(const String & odometryType) +{ + if (odometryType == "RgbdOdometry") + return makePtr(); + else if (odometryType == "ICPOdometry") + return makePtr(); + else if (odometryType == "RgbdICPOdometry") + return makePtr(); + return Ptr(); +} + // RgbdOdometry::RgbdOdometry() : minDepth(DEFAULT_MIN_DEPTH()), @@ -1229,10 +1240,15 @@ Size ICPOdometry::prepareFrameCache(Ptr& frame, int cacheType) co else { if(normalsComputer.empty() || - normalsComputer->get("rows") != frame->depth.rows || - normalsComputer->get("cols") != frame->depth.cols || - norm(normalsComputer->get("K"), cameraMatrix) > FLT_EPSILON) - normalsComputer = Ptr(new RgbdNormals(frame->depth.rows, frame->depth.cols, frame->depth.depth(), cameraMatrix, normalWinSize, normalMethod)); + normalsComputer->getRows() != frame->depth.rows || + normalsComputer->getCols() != frame->depth.cols || + norm(normalsComputer->getK(), cameraMatrix) > FLT_EPSILON) + normalsComputer = makePtr(frame->depth.rows, + frame->depth.cols, + frame->depth.depth(), + cameraMatrix, + normalWinSize, + normalMethod); (*normalsComputer)(frame->pyramidCloud[0], frame->normals); } @@ -1338,10 +1354,15 @@ Size RgbdICPOdometry::prepareFrameCache(Ptr& frame, int cacheType else { if(normalsComputer.empty() || - normalsComputer->get("rows") != frame->depth.rows || - normalsComputer->get("cols") != frame->depth.cols || - norm(normalsComputer->get("K"), cameraMatrix) > FLT_EPSILON) - normalsComputer = Ptr(new RgbdNormals(frame->depth.rows, frame->depth.cols, frame->depth.depth(), cameraMatrix, normalWinSize, normalMethod)); + normalsComputer->getRows() != frame->depth.rows || + normalsComputer->getCols() != frame->depth.cols || + norm(normalsComputer->getK(), cameraMatrix) > FLT_EPSILON) + normalsComputer = makePtr(frame->depth.rows, + frame->depth.cols, + frame->depth.depth(), + cameraMatrix, + normalWinSize, + normalMethod); (*normalsComputer)(frame->pyramidCloud[0], frame->normals); } diff --git a/modules/rgbd/src/rgbd_init.cpp b/modules/rgbd/src/rgbd_init.cpp deleted file mode 100644 index e1f14c33b..000000000 --- a/modules/rgbd/src/rgbd_init.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Software License Agreement (BSD License) - * - * Copyright (c) 2012, Willow Garage, Inc. - * All rights reserved. - * - * 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 Willow Garage, Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include "opencv2/core/utility.hpp" -#include "opencv2/core/private.hpp" - -namespace cv -{ -namespace rgbd -{ - CV_INIT_ALGORITHM(DepthCleaner, "RGBD.DepthCleaner", - obj.info()->addParam(obj, "window_size", obj.window_size_); - obj.info()->addParam(obj, "depth", obj.depth_); - obj.info()->addParam(obj, "method", obj.method_)) - - CV_INIT_ALGORITHM(RgbdNormals, "RGBD.RgbdNormals", - obj.info()->addParam(obj, "rows", obj.rows_); - obj.info()->addParam(obj, "cols", obj.cols_); - obj.info()->addParam(obj, "window_size", obj.window_size_); - obj.info()->addParam(obj, "depth", obj.depth_); - obj.info()->addParam(obj, "K", obj.K_); - obj.info()->addParam(obj, "method", obj.method_)) - - CV_INIT_ALGORITHM(RgbdPlane, "RGBD.RgbdPlane", - obj.info()->addParam(obj, "block_size", obj.block_size_); - obj.info()->addParam(obj, "min_size", obj.min_size_); - obj.info()->addParam(obj, "method", obj.method_); - obj.info()->addParam(obj, "threshold", obj.threshold_); - obj.info()->addParam(obj, "sensor_error_a", obj.sensor_error_a_); - obj.info()->addParam(obj, "sensor_error_b", obj.sensor_error_b_); - obj.info()->addParam(obj, "sensor_error_c", obj.sensor_error_c_)) - - CV_INIT_ALGORITHM(RgbdOdometry, "RGBD.RgbdOdometry", - obj.info()->addParam(obj, "cameraMatrix", obj.cameraMatrix); - obj.info()->addParam(obj, "minDepth", obj.minDepth); - obj.info()->addParam(obj, "maxDepth", obj.maxDepth); - obj.info()->addParam(obj, "maxDepthDiff", obj.maxDepthDiff); - obj.info()->addParam(obj, "iterCounts", obj.iterCounts); - obj.info()->addParam(obj, "minGradientMagnitudes", obj.minGradientMagnitudes); - obj.info()->addParam(obj, "maxPointsPart", obj.maxPointsPart); - obj.info()->addParam(obj, "transformType", obj.transformType); - obj.info()->addParam(obj, "maxTranslation", obj.maxTranslation); - obj.info()->addParam(obj, "maxRotation", obj.maxRotation);) - - CV_INIT_ALGORITHM(ICPOdometry, "RGBD.ICPOdometry", - obj.info()->addParam(obj, "cameraMatrix", obj.cameraMatrix); - obj.info()->addParam(obj, "minDepth", obj.minDepth); - obj.info()->addParam(obj, "maxDepth", obj.maxDepth); - obj.info()->addParam(obj, "maxDepthDiff", obj.maxDepthDiff); - obj.info()->addParam(obj, "maxPointsPart", obj.maxPointsPart); - obj.info()->addParam(obj, "iterCounts", obj.iterCounts); - obj.info()->addParam(obj, "transformType", obj.transformType); - obj.info()->addParam(obj, "maxTranslation", obj.maxTranslation); - obj.info()->addParam(obj, "maxRotation", obj.maxRotation); - obj.info()->addParam(obj, "normalsComputer", obj.normalsComputer, true, NULL, NULL);) - - CV_INIT_ALGORITHM(RgbdICPOdometry, "RGBD.RgbdICPOdometry", - obj.info()->addParam(obj, "cameraMatrix", obj.cameraMatrix); - obj.info()->addParam(obj, "minDepth", obj.minDepth); - obj.info()->addParam(obj, "maxDepth", obj.maxDepth); - obj.info()->addParam(obj, "maxDepthDiff", obj.maxDepthDiff); - obj.info()->addParam(obj, "maxPointsPart", obj.maxPointsPart); - obj.info()->addParam(obj, "iterCounts", obj.iterCounts); - obj.info()->addParam(obj, "minGradientMagnitudes", obj.minGradientMagnitudes); - obj.info()->addParam(obj, "transformType", obj.transformType); - obj.info()->addParam(obj, "maxTranslation", obj.maxTranslation); - obj.info()->addParam(obj, "maxRotation", obj.maxRotation); - obj.info()->addParam(obj, "normalsComputer", obj.normalsComputer, true, NULL, NULL);) - - bool - initModule_rgbd(void); - bool - initModule_rgbd(void) - { - bool all = true; - all &= !RgbdNormals_info_auto.name().empty(); - all &= !RgbdPlane_info_auto.name().empty(); - all &= !RgbdOdometry_info_auto.name().empty(); - all &= !ICPOdometry_info_auto.name().empty(); - all &= !RgbdICPOdometry_info_auto.name().empty(); - return all; - } -} -} - diff --git a/modules/rgbd/test/test_normal.cpp b/modules/rgbd/test/test_normal.cpp index 278f24415..95e3251e2 100644 --- a/modules/rgbd/test/test_normal.cpp +++ b/modules/rgbd/test/test_normal.cpp @@ -309,7 +309,7 @@ protected: TickMeter tm; tm.start(); Mat in_normals; - if (normals_computer.method() == RgbdNormals::RGBD_NORMALS_METHOD_LINEMOD) + if (normals_computer.getMethod() == RgbdNormals::RGBD_NORMALS_METHOD_LINEMOD) { std::vector channels; split(points3d, channels); diff --git a/modules/rgbd/test/test_odometry.cpp b/modules/rgbd/test/test_odometry.cpp index b73c74ded..c95720e1e 100644 --- a/modules/rgbd/test/test_odometry.cpp +++ b/modules/rgbd/test/test_odometry.cpp @@ -241,7 +241,7 @@ void CV_OdometryTest::run(int) if(!readData(image, depth)) return; - odometry->set("cameraMatrix", K); + odometry->setCameraMatrix(K); Mat calcRt; @@ -338,18 +338,18 @@ void CV_OdometryTest::run(int) TEST(RGBD_Odometry_Rgbd, algorithmic) { - cv::rgbd::CV_OdometryTest test(cv::Algorithm::create("RGBD.RgbdOdometry"), 0.99, 0.94); + cv::rgbd::CV_OdometryTest test(cv::rgbd::Odometry::create("RGBD.RgbdOdometry"), 0.99, 0.94); test.safe_run(); } TEST(RGBD_Odometry_ICP, algorithmic) { - cv::rgbd::CV_OdometryTest test(cv::Algorithm::create("RGBD.ICPOdometry"), 0.99, 0.99); + cv::rgbd::CV_OdometryTest test(cv::rgbd::Odometry::create("RGBD.ICPOdometry"), 0.99, 0.99); test.safe_run(); } TEST(RGBD_Odometry_RgbdICP, algorithmic) { - cv::rgbd::CV_OdometryTest test(cv::Algorithm::create("RGBD.RgbdICPOdometry"), 0.99, 0.99); + cv::rgbd::CV_OdometryTest test(cv::rgbd::Odometry::create("RGBD.RgbdICPOdometry"), 0.99, 0.99); test.safe_run(); } diff --git a/modules/saliency/include/opencv2/saliency.hpp b/modules/saliency/include/opencv2/saliency.hpp index c86e11dd3..56bfe8a04 100644 --- a/modules/saliency/include/opencv2/saliency.hpp +++ b/modules/saliency/include/opencv2/saliency.hpp @@ -80,12 +80,4 @@ To see how API works, try tracker demo: */ -namespace cv -{ -namespace saliency -{ -CV_EXPORTS bool initModule_saliency( void ); -} -} - #endif //__OPENCV_SALIENCY_HPP__ diff --git a/modules/saliency/include/opencv2/saliency/saliencySpecializedClasses.hpp b/modules/saliency/include/opencv2/saliency/saliencySpecializedClasses.hpp index a826ba1b6..326d91e20 100644 --- a/modules/saliency/include/opencv2/saliency/saliencySpecializedClasses.hpp +++ b/modules/saliency/include/opencv2/saliency/saliencySpecializedClasses.hpp @@ -47,6 +47,7 @@ #include #include #include +#include "opencv2/core.hpp" namespace cv { @@ -75,9 +76,11 @@ public: void read( const FileNode& fn ); void write( FileStorage& fs ) const; + CV_IMPL_PROPERTY(int, ImageWidth, resImWidth) + CV_IMPL_PROPERTY(int, ImageHeight, resImHeight) + protected: bool computeSaliencyImpl( const InputArray image, OutputArray saliencyMap ); - AlgorithmInfo* info() const; int resImWidth; int resImHeight; @@ -111,6 +114,9 @@ public: */ bool init(); + CV_IMPL_PROPERTY(int, ImageWidth, imageWidth) + CV_IMPL_PROPERTY(int, ImageHeight, imageHeight) + protected: /** @brief Performs all the operations and calls all internal functions necessary for the accomplishment of the Fast Self-tuning Background Subtraction Algorithm algorithm. @@ -121,7 +127,6 @@ protected: stream). */ bool computeSaliencyImpl( const InputArray image, OutputArray saliencyMap ); - AlgorithmInfo* info() const; private: @@ -200,6 +205,10 @@ public: */ void setBBResDir( std::string resultsDir ); + CV_IMPL_PROPERTY(double, Base, _base) + CV_IMPL_PROPERTY(int, NSS, _NSS) + CV_IMPL_PROPERTY(int, W, _W) + protected: /** @brief Performs all the operations and calls all internal functions necessary for the accomplishment of the Binarized normed gradients algorithm. @@ -211,7 +220,6 @@ protected: represented by a *Vec4i* for (minX, minY, maxX, maxY). */ bool computeSaliencyImpl( const InputArray image, OutputArray objectnessBoundingBox ); - AlgorithmInfo* info() const; private: diff --git a/modules/saliency/src/saliency.cpp b/modules/saliency/src/saliency.cpp index f05691568..5e86f46df 100644 --- a/modules/saliency/src/saliency.cpp +++ b/modules/saliency/src/saliency.cpp @@ -53,9 +53,13 @@ Saliency::~Saliency() Ptr Saliency::create( const String& saliencyType ) { - - return Algorithm::create( "SALIENCY." + saliencyType ); - + if (saliencyType == "SPECTRAL_RESIDUAL") + return makePtr(); + else if (saliencyType == "BING") + return makePtr(); + else if (saliencyType == "BinWangApr2014") + return makePtr(); + return Ptr(); } bool Saliency::computeSaliency( const InputArray image, OutputArray saliencyMap ) diff --git a/modules/saliency/src/saliency_init.cpp b/modules/saliency/src/saliency_init.cpp deleted file mode 100644 index 81f1cc56e..000000000 --- a/modules/saliency/src/saliency_init.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// - // - // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. - // - // By downloading, copying, installing or using the software you agree to this license. - // If you do not agree to this license, do not download, install, - // copy or use the software. - // - // - // License Agreement - // For Open Source Computer Vision Library - // - // Copyright (C) 2014, OpenCV Foundation, all rights reserved. - // Third party copyrights are property of their respective owners. - // - // Redistribution and use in source and binary forms, with or without modification, - // are permitted provided that the following conditions are met: - // - // * Redistribution's of source code must retain the above copyright notice, - // this list of conditions and the following disclaimer. - // - // * Redistribution's 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. - // - // * The name of the copyright holders may not be used to endorse or promote products - // derived from this software without specific prior written permission. - // - // This software is provided by the copyright holders and contributors "as is" and - // any express or implied warranties, including, but not limited to, the implied - // warranties of merchantability and fitness for a particular purpose are disclaimed. - // In no event shall the Intel Corporation or contributors be liable for any direct, - // indirect, incidental, special, exemplary, or consequential damages - // (including, but not limited to, procurement of substitute goods or services; - // loss of use, data, or profits; or business interruption) however caused - // and on any theory of liability, whether in contract, strict liability, - // or tort (including negligence or otherwise) arising in any way out of - // the use of this software, even if advised of the possibility of such damage. - // - //M*/ - -#include "precomp.hpp" -#include "opencv2/saliency.hpp" - -namespace cv -{ -namespace saliency -{ - -CV_INIT_ALGORITHM( StaticSaliencySpectralResidual, "SALIENCY.SPECTRAL_RESIDUAL", - obj.info()->addParam( obj, "resImWidth", obj.resImWidth); obj.info()->addParam( obj, "resImHeight", obj.resImHeight) ); - - -CV_INIT_ALGORITHM( - ObjectnessBING, "SALIENCY.BING", - obj.info()->addParam(obj, "_base", obj._base); obj.info()->addParam(obj, "_NSS", obj._NSS); obj.info()->addParam(obj, "_W", obj._W) ); - -CV_INIT_ALGORITHM( MotionSaliencyBinWangApr2014, "SALIENCY.BinWangApr2014", - obj.info()->addParam( obj, "imageWidth", obj.imageWidth); obj.info()->addParam( obj, "imageHeight", obj.imageHeight) ); - -bool initModule_saliency( void ) -{ - bool all = true; - all &= !StaticSaliencySpectralResidual_info_auto.name().empty(); - //all &= !MotionSaliencySuBSENSE_info_auto.name().empty(); - all &= !MotionSaliencyBinWangApr2014_info_auto.name().empty(); - all &= !ObjectnessBING_info_auto.name().empty(); - - return all; -} - -} // namespace saliency -} // namespace cv diff --git a/modules/tracking/include/opencv2/tracking.hpp b/modules/tracking/include/opencv2/tracking.hpp index c4ab41fdd..f3e0ed001 100644 --- a/modules/tracking/include/opencv2/tracking.hpp +++ b/modules/tracking/include/opencv2/tracking.hpp @@ -327,10 +327,6 @@ The first argument is the name of the tracker and the second is a video source. */ -namespace cv -{ -CV_EXPORTS bool initModule_tracking(void); -} - #include "opencv2/tracking/tracker.hpp" + #endif //__OPENCV_TRACKING_LENLEN diff --git a/modules/tracking/include/opencv2/tracking/tracker.hpp b/modules/tracking/include/opencv2/tracking/tracker.hpp index de1a94fff..324112711 100644 --- a/modules/tracking/include/opencv2/tracking/tracker.hpp +++ b/modules/tracking/include/opencv2/tracking/tracker.hpp @@ -574,7 +574,6 @@ class CV_EXPORTS_W Tracker : public virtual Algorithm Ptr featureSet; Ptr sampler; Ptr model; - virtual AlgorithmInfo* info() const; }; /************************************ Specific TrackerStateEstimator Classes ************************************/ diff --git a/modules/tracking/src/tracker.cpp b/modules/tracking/src/tracker.cpp index ca6da2357..58a46b150 100644 --- a/modules/tracking/src/tracker.cpp +++ b/modules/tracking/src/tracker.cpp @@ -104,10 +104,6 @@ bool Tracker::update( const Mat& image, Rect2d& boundingBox ) return updateImpl( image, boundingBox ); } -AlgorithmInfo* Tracker::info() const{ - return 0; -} - Ptr Tracker::create( const String& trackerType ) { BOILERPLATE_CODE("MIL",TrackerMIL); diff --git a/modules/tracking/src/tracking_init.cpp b/modules/tracking/src/tracking_init.cpp deleted file mode 100644 index ffe31dfc4..000000000 --- a/modules/tracking/src/tracking_init.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// - // - // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. - // - // By downloading, copying, installing or using the software you agree to this license. - // If you do not agree to this license, do not download, install, - // copy or use the software. - // - // - // License Agreement - // For Open Source Computer Vision Library - // - // Copyright (C) 2013, OpenCV Foundation, all rights reserved. - // Third party copyrights are property of their respective owners. - // - // Redistribution and use in source and binary forms, with or without modification, - // are permitted provided that the following conditions are met: - // - // * Redistribution's of source code must retain the above copyright notice, - // this list of conditions and the following disclaimer. - // - // * Redistribution's 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. - // - // * The name of the copyright holders may not be used to endorse or promote products - // derived from this software without specific prior written permission. - // - // This software is provided by the copyright holders and contributors "as is" and - // any express or implied warranties, including, but not limited to, the implied - // warranties of merchantability and fitness for a particular purpose are disclaimed. - // In no event shall the Intel Corporation or contributors be liable for any direct, - // indirect, incidental, special, exemplary, or consequential damages - // (including, but not limited to, procurement of substitute goods or services; - // loss of use, data, or profits; or business interruption) however caused - // and on any theory of liability, whether in contract, strict liability, - // or tort (including negligence or otherwise) arising in any way out of - // the use of this software, even if advised of the possibility of such damage. - // - //M*/ - -#include "precomp.hpp" -#include "opencv2/tracking.hpp" - -namespace cv -{ - -bool initModule_tracking(void) -{ - return true; -} - -} diff --git a/modules/xfeatures2d/include/opencv2/xfeatures2d/cuda.hpp b/modules/xfeatures2d/include/opencv2/xfeatures2d/cuda.hpp index 3dc57c7ff..16039a5a7 100644 --- a/modules/xfeatures2d/include/opencv2/xfeatures2d/cuda.hpp +++ b/modules/xfeatures2d/include/opencv2/xfeatures2d/cuda.hpp @@ -152,7 +152,7 @@ public: //! max keypoints = min(keypointsRatio * img.size().area(), 65535) float keypointsRatio; - GpuMat sum, mask1, maskSum, intBuffer; + GpuMat sum, mask1, maskSum; GpuMat det, trace; diff --git a/modules/xfeatures2d/samples/bagofwords_classification.cpp b/modules/xfeatures2d/samples/bagofwords_classification.cpp index 3ad77ba66..b281531ea 100644 --- a/modules/xfeatures2d/samples/bagofwords_classification.cpp +++ b/modules/xfeatures2d/samples/bagofwords_classification.cpp @@ -2327,14 +2327,14 @@ static void removeBowImageDescriptorsByCount( vector& images, vector & svm, const Mat& responses, bool balanceClasses ) { int pos_ex = countNonZero(responses == 1); int neg_ex = countNonZero(responses == -1); cout << pos_ex << " positive training samples; " << neg_ex << " negative training samples" << endl; - svmParams.svmType = SVM::C_SVC; - svmParams.kernelType = SVM::RBF; + svm->setType(SVM::C_SVC); + svm->setKernel(SVM::RBF); if( balanceClasses ) { Mat class_wts( 2, 1, CV_32FC1 ); @@ -2351,8 +2351,7 @@ static void setSVMParams( SVM::Params& svmParams, Mat& class_wts_cv, const Mat& class_wts.at(0) = static_cast(neg_ex)/static_cast(pos_ex+neg_ex); class_wts.at(1) = static_cast(pos_ex)/static_cast(pos_ex+neg_ex); } - class_wts_cv = class_wts; - svmParams.classWeights = class_wts_cv; + svm->setClassWeights(class_wts); } } @@ -2440,10 +2439,8 @@ static Ptr trainSVMClassifier( const SVMTrainParamsExt& svmParamsExt, const } cout << "TRAINING SVM FOR CLASS ..." << objClassName << "..." << endl; - SVM::Params svmParams; - Mat class_wts_cv; - setSVMParams( svmParams, class_wts_cv, responses, svmParamsExt.balanceClasses ); - svm = SVM::create(svmParams); + svm = SVM::create(); + setSVMParams( svm, responses, svmParamsExt.balanceClasses ); ParamGrid c_grid, gamma_grid, p_grid, nu_grid, coef_grid, degree_grid; setSVMTrainAutoParams( c_grid, gamma_grid, p_grid, nu_grid, coef_grid, degree_grid ); diff --git a/modules/xfeatures2d/src/surf.cuda.cpp b/modules/xfeatures2d/src/surf.cuda.cpp index 208156c98..6f7a0f45f 100644 --- a/modules/xfeatures2d/src/surf.cuda.cpp +++ b/modules/xfeatures2d/src/surf.cuda.cpp @@ -146,13 +146,13 @@ namespace bindImgTex(img); - cuda::integral(img, surf_.sum, surf_.intBuffer); + cuda::integral(img, surf_.sum); sumOffset = bindSumTex(surf_.sum); if (use_mask) { cuda::min(mask, 1.0, surf_.mask1); - cuda::integral(surf_.mask1, surf_.maskSum, surf_.intBuffer); + cuda::integral(surf_.mask1, surf_.maskSum); maskOffset = bindMaskSumTex(surf_.maskSum); } } @@ -425,7 +425,6 @@ void cv::cuda::SURF_CUDA::releaseMemory() sum.release(); mask1.release(); maskSum.release(); - intBuffer.release(); det.release(); trace.release(); maxPosBuffer.release(); diff --git a/modules/ximgproc/include/opencv2/ximgproc/edge_filter.hpp b/modules/ximgproc/include/opencv2/ximgproc/edge_filter.hpp index 60132e0f2..f9611a16a 100644 --- a/modules/ximgproc/include/opencv2/ximgproc/edge_filter.hpp +++ b/modules/ximgproc/include/opencv2/ximgproc/edge_filter.hpp @@ -216,6 +216,13 @@ public: CV_WRAP virtual void collectGarbage() = 0; CV_WRAP static Ptr create(); + + CV_PURE_PROPERTY(double, SigmaS) + CV_PURE_PROPERTY(double, SigmaR) + CV_PURE_PROPERTY(int, TreeHeight) + CV_PURE_PROPERTY(int, PCAIterations) + CV_PURE_PROPERTY(bool, AdjustOutliers) + CV_PURE_PROPERTY(bool, UseRNG) }; /** @brief Factory method, create instance of AdaptiveManifoldFilter and produce some initialization routines. diff --git a/modules/ximgproc/src/adaptive_manifold_filter_n.cpp b/modules/ximgproc/src/adaptive_manifold_filter_n.cpp index 98ee98f3a..3d400a4bc 100644 --- a/modules/ximgproc/src/adaptive_manifold_filter_n.cpp +++ b/modules/ximgproc/src/adaptive_manifold_filter_n.cpp @@ -107,14 +107,19 @@ static void splitChannels(InputArrayOfArrays src, vector& dst) class AdaptiveManifoldFilterN : public AdaptiveManifoldFilter { public: - AlgorithmInfo* info() const; - AdaptiveManifoldFilterN(); void filter(InputArray src, OutputArray dst, InputArray joint); void collectGarbage(); + CV_IMPL_PROPERTY(double, SigmaS, sigma_s_) + CV_IMPL_PROPERTY(double, SigmaR, sigma_r_) + CV_IMPL_PROPERTY(int, TreeHeight, tree_height_) + CV_IMPL_PROPERTY(int, PCAIterations, num_pca_iterations_) + CV_IMPL_PROPERTY(bool, AdjustOutliers, adjust_outliers_) + CV_IMPL_PROPERTY(bool, UseRNG, useRNG) + protected: bool adjust_outliers_; @@ -261,14 +266,6 @@ private: /*Parallelization routines*/ }; -CV_INIT_ALGORITHM(AdaptiveManifoldFilterN, "AdaptiveManifoldFilter", - obj.info()->addParam(obj, "sigma_s", obj.sigma_s_, false, 0, 0, "Filter spatial standard deviation"); - obj.info()->addParam(obj, "sigma_r", obj.sigma_r_, false, 0, 0, "Filter range standard deviation"); - obj.info()->addParam(obj, "tree_height", obj.tree_height_, false, 0, 0, "Height of the manifold tree (default = -1 : automatically computed)"); - obj.info()->addParam(obj, "num_pca_iterations", obj.num_pca_iterations_, false, 0, 0, "Number of iterations to computed the eigenvector v1"); - obj.info()->addParam(obj, "adjust_outliers", obj.adjust_outliers_, false, 0, 0, "Specify adjust outliers using Eq. 9 or not"); - obj.info()->addParam(obj, "use_RNG", obj.useRNG, false, 0, 0, "Specify use random to compute eigenvector or not");) - AdaptiveManifoldFilterN::AdaptiveManifoldFilterN() { sigma_s_ = 16.0; @@ -852,19 +849,17 @@ Ptr AdaptiveManifoldFilter::create() return Ptr(new AdaptiveManifoldFilterN()); } -CV_EXPORTS_W Ptr createAMFilter(double sigma_s, double sigma_r, bool adjust_outliers) { Ptr amf(new AdaptiveManifoldFilterN()); - amf->set("sigma_s", sigma_s); - amf->set("sigma_r", sigma_r); - amf->set("adjust_outliers", adjust_outliers); + amf->setSigmaS(sigma_s); + amf->setSigmaR(sigma_r); + amf->setAdjustOutliers(adjust_outliers); return amf; } -CV_EXPORTS_W void amFilter(InputArray joint, InputArray src, OutputArray dst, double sigma_s, double sigma_r, bool adjust_outliers) { Ptr amf = createAMFilter(sigma_s, sigma_r, adjust_outliers); @@ -872,4 +867,4 @@ void amFilter(InputArray joint, InputArray src, OutputArray dst, double sigma_s, } } -} \ No newline at end of file +} diff --git a/modules/ximgproc/test/test_adaptive_manifold.cpp b/modules/ximgproc/test/test_adaptive_manifold.cpp index a8970041c..12f9686b4 100644 --- a/modules/ximgproc/test/test_adaptive_manifold.cpp +++ b/modules/ximgproc/test/test_adaptive_manifold.cpp @@ -139,7 +139,7 @@ TEST(AdaptiveManifoldTest, AuthorsReferenceAccuracy) Mat res; Ptr amf = createAMFilter(sigma_s, sigma_r, false); - amf->setBool("use_RNG", false); + amf->setUseRNG(false); amf->filter(srcImg, res, srcImg); amf->collectGarbage(); @@ -155,7 +155,7 @@ TEST(AdaptiveManifoldTest, AuthorsReferenceAccuracy) Mat res; Ptr amf = createAMFilter(sigma_s, sigma_r, true); - amf->setBool("use_RNG", false); + amf->setUseRNG(false); amf->filter(srcImg, res, srcImg); amf->collectGarbage(); @@ -216,4 +216,4 @@ INSTANTIATE_TEST_CASE_P(TypicalSet, AdaptiveManifoldRefImplTest, Values("cv/shared/lena.png", "cv/edgefilter/kodim23.png", "cv/npr/test4.png") )); -} \ No newline at end of file +} diff --git a/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp b/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp index b71a33e4c..70d329e8e 100644 --- a/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp +++ b/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp @@ -179,14 +179,19 @@ namespace class AdaptiveManifoldFilterRefImpl : public AdaptiveManifoldFilter { public: - AlgorithmInfo* info() const; - AdaptiveManifoldFilterRefImpl(); void filter(InputArray src, OutputArray dst, InputArray joint); void collectGarbage(); + CV_IMPL_PROPERTY(double, SigmaS, sigma_s_) + CV_IMPL_PROPERTY(double, SigmaR, sigma_r_) + CV_IMPL_PROPERTY(int, TreeHeight, tree_height_) + CV_IMPL_PROPERTY(int, PCAIterations, num_pca_iterations_) + CV_IMPL_PROPERTY(bool, AdjustOutliers, adjust_outliers_) + CV_IMPL_PROPERTY(bool, UseRNG, useRNG) + protected: bool adjust_outliers_; double sigma_s_; @@ -237,14 +242,6 @@ namespace min_pixel_dist_to_manifold_squared_.release(); } - CV_INIT_ALGORITHM(AdaptiveManifoldFilterRefImpl, "AdaptiveManifoldFilterRefImpl", - obj.info()->addParam(obj, "sigma_s", obj.sigma_s_, false, 0, 0, "Filter spatial standard deviation"); - obj.info()->addParam(obj, "sigma_r", obj.sigma_r_, false, 0, 0, "Filter range standard deviation"); - obj.info()->addParam(obj, "tree_height", obj.tree_height_, false, 0, 0, "Height of the manifold tree (default = -1 : automatically computed)"); - obj.info()->addParam(obj, "num_pca_iterations", obj.num_pca_iterations_, false, 0, 0, "Number of iterations to computed the eigenvector v1"); - obj.info()->addParam(obj, "adjust_outliers", obj.adjust_outliers_, false, 0, 0, "Specify supress outliers using Eq. 9 or not"); - obj.info()->addParam(obj, "use_RNG", obj.useRNG, false, 0, 0, "Specify use random to compute eigenvector or not");) - inline double Log2(double n) { return log(n) / log(2.0); @@ -974,11 +971,11 @@ Ptr createAMFilterRefImpl(double sigma_s, double sigma_r { Ptr amf(new AdaptiveManifoldFilterRefImpl()); - amf->set("sigma_s", sigma_s); - amf->set("sigma_r", sigma_r); - amf->set("adjust_outliers", adjust_outliers); + amf->setSigmaS(sigma_s); + amf->setSigmaR(sigma_r); + amf->setAdjustOutliers(adjust_outliers); return amf; } -} \ No newline at end of file +} diff --git a/modules/xobjdetect/include/opencv2/xobjdetect.hpp b/modules/xobjdetect/include/opencv2/xobjdetect.hpp index 3086d52eb..4d05ea97c 100644 --- a/modules/xobjdetect/include/opencv2/xobjdetect.hpp +++ b/modules/xobjdetect/include/opencv2/xobjdetect.hpp @@ -153,17 +153,6 @@ public: */ virtual float predict( const Ptr& feature_evaluator) const = 0; - - /** @brief Write WaldBoost to FileStorage - @param fs FileStorage for output - */ - virtual void write(FileStorage& fs) const = 0; - - /** @brief Write WaldBoost to FileNode - - @param node FileNode for reading - */ - virtual void read(const FileNode& node) = 0; }; /** @brief Construct WaldBoost object.