From 4ca8e1a4ee562f7df3382d76ef078d151304e09b Mon Sep 17 00:00:00 2001 From: saiteja-talluri Date: Tue, 6 Aug 2019 19:26:10 +0530 Subject: [PATCH 1/2] Updated with latest master --- .../include/opencv2/face/face_alignment.hpp | 24 ++---- .../face/include/opencv2/face/facemark.hpp | 76 ++++++++++++++++++ .../face/include/opencv2/face/facemarkAAM.hpp | 1 + .../include/opencv2/face/facemark_train.hpp | 73 +----------------- .../sample_train_landmark_detector.cpp | 15 ++-- .../sample_train_landmark_detector2.cpp | 13 ++-- modules/face/src/face_alignment.cpp | 74 +++++++++++++++++- modules/face/src/face_alignmentimpl.hpp | 11 ++- modules/face/src/facemark.cpp | 6 +- modules/face/src/facemarkAAM.cpp | 77 ++++++++++++++++--- modules/face/src/facemarkLBF.cpp | 27 +++++-- modules/face/src/trainFacemark.cpp | 30 ++++---- modules/face/test/test_face_align.cpp | 17 ++-- 13 files changed, 302 insertions(+), 142 deletions(-) diff --git a/modules/face/include/opencv2/face/face_alignment.hpp b/modules/face/include/opencv2/face/face_alignment.hpp index 612bce12c96..466f355d345 100644 --- a/modules/face/include/opencv2/face/face_alignment.hpp +++ b/modules/face/include/opencv2/face/face_alignment.hpp @@ -8,7 +8,7 @@ namespace cv{ namespace face{ -class CV_EXPORTS_W FacemarkKazemi : public Facemark +class CV_EXPORTS_W FacemarkKazemi : public FacemarkTrain { public: struct CV_EXPORTS Params @@ -35,25 +35,15 @@ class CV_EXPORTS_W FacemarkKazemi : public Facemark unsigned long num_test_splits; /// configfile stores the name of the file containing the values of training parameters String configfile; + /// modelfile stores the name of the file containing the Kazemi model + String modelfile; + /// faceCascadefile stores the name of the file containing the face cascade model + String faceCascadefile; + /// scale to which all the images and the landmarks need to be scaled + Size scale; }; static Ptr create(const FacemarkKazemi::Params ¶meters = FacemarkKazemi::Params()); virtual ~FacemarkKazemi(); - - /** @brief This function is used to train the model using gradient boosting to get a cascade of regressors - *which can then be used to predict shape. - *@param images A vector of type cv::Mat which stores the images which are used in training samples. - *@param landmarks A vector of vectors of type cv::Point2f which stores the landmarks detected in a particular image. - *@param scale A size of type cv::Size to which all images and landmarks have to be scaled to. - *@param configfile A variable of type std::string which stores the name of the file storing parameters for training the model. - *@param modelFilename A variable of type std::string which stores the name of the trained model file that has to be saved. - *@returns A boolean value. The function returns true if the model is trained properly or false if it is not trained. - */ - virtual bool training(std::vector& images, std::vector< std::vector >& landmarks,std::string configfile,Size scale,std::string modelFilename = "face_landmarks.dat")=0; - - /// set the custom face detector - virtual bool setFaceDetector(bool(*f)(InputArray , OutputArray, void*), void* userData)=0; - /// get faces using the custom detector - virtual bool getFaces(InputArray image, OutputArray faces)=0; }; }} // namespace diff --git a/modules/face/include/opencv2/face/facemark.hpp b/modules/face/include/opencv2/face/facemark.hpp index 86e9384342e..c320e8458e2 100644 --- a/modules/face/include/opencv2/face/facemark.hpp +++ b/modules/face/include/opencv2/face/facemark.hpp @@ -76,6 +76,82 @@ class CV_EXPORTS_W Facemark : public virtual Algorithm CV_WRAP virtual bool fit( InputArray image, InputArray faces, OutputArrayOfArrays landmarks) = 0; + + /** @brief Add one training sample to the trainer. + + @param image Input image. + @param landmarks The ground-truth of facial landmarks points corresponds to the image. + + Example of usage + @code + String imageFiles = "../data/images_train.txt"; + String ptsFiles = "../data/points_train.txt"; + std::vector images_train; + std::vector landmarks_train; + + // load the list of dataset: image paths and landmark file paths + loadDatasetList(imageFiles,ptsFiles,images_train,landmarks_train); + + Mat image; + std::vector facial_points; + for(size_t i=0;iaddTrainingSample(image, facial_points); + } + @endcode + + The contents in the training files should follows the standard format. + Here are examples for the contents in these files. + example of content in the images_train.txt + @code + /home/user/ibug/image_003_1.jpg + /home/user/ibug/image_004_1.jpg + /home/user/ibug/image_005_1.jpg + /home/user/ibug/image_006.jpg + @endcode + + example of content in the points_train.txt + @code + /home/user/ibug/image_003_1.pts + /home/user/ibug/image_004_1.pts + /home/user/ibug/image_005_1.pts + /home/user/ibug/image_006.pts + @endcode + + */ + CV_WRAP virtual bool addTrainingSample(InputArray image, std::vector & landmarks)=0; + + /** @brief Set parameters in the Facemark Instance. + + @param face_cascade_name Path to the face cascade model + @param facemark_model_name Path to the facemark model + @param config_file_path Path to the Config file (only for FacemarkKazemi) + @param scale vector of floats represent scale (only for FacemarkAAM, FacemarkKazemi) + + Example of usage + @code + facemark->setParams(filename,modelfilename,configfile_name,scale) + @endcode + */ + CV_WRAP virtual bool setParams(const String& face_cascade_name,const String& facemark_model_name, const String& config_file_path, InputArray scale)=0; + + /** @brief Trains a Facemark algorithm using the given dataset. + Before the training process, training samples should be added to the trainer + using face::addTrainingSample function. + + Example of usage + @code + FacemarkLBF::Params params; + params.model_filename = "ibug68.model"; // filename to save the trained model + Ptr facemark = FacemarkLBF::create(params); + + // add training samples (see Facemark::addTrainingSample) + + facemark->training(); + @endcode + */ + CV_WRAP virtual void training()=0; }; /* Facemark*/ diff --git a/modules/face/include/opencv2/face/facemarkAAM.hpp b/modules/face/include/opencv2/face/facemarkAAM.hpp index 6f96e4a22fd..6b4dd40bf1b 100644 --- a/modules/face/include/opencv2/face/facemarkAAM.hpp +++ b/modules/face/include/opencv2/face/facemarkAAM.hpp @@ -65,6 +65,7 @@ class CV_EXPORTS_W FacemarkAAM : public FacemarkTrain void write(FileStorage& /*fs*/) const; std::string model_filename; + std::string cascade_filename; int m; int n; int n_iter; diff --git a/modules/face/include/opencv2/face/facemark_train.hpp b/modules/face/include/opencv2/face/facemark_train.hpp index 33ecb946403..b55d07fcd6e 100644 --- a/modules/face/include/opencv2/face/facemark_train.hpp +++ b/modules/face/include/opencv2/face/facemark_train.hpp @@ -92,8 +92,8 @@ loadDatasetList(imageFiles,ptsFiles,images_train,landmarks_train); */ CV_EXPORTS_W bool loadDatasetList(String imageList, String annotationList, - std::vector & images, - std::vector & annotations); + CV_OUT std::vector & images, + CV_OUT std::vector & annotations); /** @brief A utility to load facial landmark dataset from a single file. @@ -181,8 +181,8 @@ CV_EXPORTS_W bool loadTrainingData( String imageList, String groundTruth, * @param trainimages A vector of type cv::String which stores the name of images whose landmarks are tracked * @returns A boolean value. It returns true when it reads the data successfully and false otherwise */ -CV_EXPORTS_W bool loadTrainingData(std::vector filename,std::vector< std::vector > - &trainlandmarks,std::vector & trainimages); +CV_EXPORTS_W bool loadTrainingData(std::vector filename, CV_OUT std::vector< std::vector > + &trainlandmarks, CV_OUT std::vector & trainimages); /** @brief A utility to load facial landmark information from a given file. @@ -262,71 +262,6 @@ The typical pipeline for facemark detection is listed as follows: class CV_EXPORTS_W FacemarkTrain : public Facemark { public: - /** @brief Add one training sample to the trainer. - - @param image Input image. - @param landmarks The ground-truth of facial landmarks points corresponds to the image. - - Example of usage - @code - String imageFiles = "../data/images_train.txt"; - String ptsFiles = "../data/points_train.txt"; - std::vector images_train; - std::vector landmarks_train; - - // load the list of dataset: image paths and landmark file paths - loadDatasetList(imageFiles,ptsFiles,images_train,landmarks_train); - - Mat image; - std::vector facial_points; - for(size_t i=0;iaddTrainingSample(image, facial_points); - } - @endcode - - The contents in the training files should follows the standard format. - Here are examples for the contents in these files. - example of content in the images_train.txt - @code - /home/user/ibug/image_003_1.jpg - /home/user/ibug/image_004_1.jpg - /home/user/ibug/image_005_1.jpg - /home/user/ibug/image_006.jpg - @endcode - - example of content in the points_train.txt - @code - /home/user/ibug/image_003_1.pts - /home/user/ibug/image_004_1.pts - /home/user/ibug/image_005_1.pts - /home/user/ibug/image_006.pts - @endcode - - */ - virtual bool addTrainingSample(InputArray image, InputArray landmarks)=0; - - /** @brief Trains a Facemark algorithm using the given dataset. - Before the training process, training samples should be added to the trainer - using face::addTrainingSample function. - - @param parameters Optional extra parameters (algorithm dependent). - - Example of usage - @code - FacemarkLBF::Params params; - params.model_filename = "ibug68.model"; // filename to save the trained model - Ptr facemark = FacemarkLBF::create(params); - - // add training samples (see Facemark::addTrainingSample) - - facemark->training(); - @endcode - */ - - virtual void training(void* parameters=0)=0; - /** @brief Set a user defined face detector for the Facemark algorithm. @param detector The user defined face detector function @param userData Detector parameters diff --git a/modules/face/samples/sample_train_landmark_detector.cpp b/modules/face/samples/sample_train_landmark_detector.cpp index 71a196f5e9e..ee5b3ab08e8 100644 --- a/modules/face/samples/sample_train_landmark_detector.cpp +++ b/modules/face/samples/sample_train_landmark_detector.cpp @@ -89,15 +89,19 @@ int main(int argc,char** argv){ face_cascade.load(cascade_name); FacemarkKazemi::Params params; params.configfile = configfile_name; + params.faceCascadefile = cascade_name; + params.modelfile = modelfile_name; + params.scale = scale; Ptr facemark = FacemarkKazemi::create(params); + // std::vector scale(2, 460); + // facemark->setParams(cascade_name,modelfile_name,configfile_name,scale); facemark->setFaceDetector((FN_FaceDetector)myDetector, &face_cascade); //create a vector to store image names vector imagenames; //create object to get landmarks - vector< vector > trainlandmarks,Trainlandmarks; + vector< vector > trainlandmarks; //gets landmarks and corresponding image names in both the vectors //vector to store images - vector trainimages; loadTrainingData(filenames,trainlandmarks,imagenames); for(unsigned long i=0;i<300;i++){ string imgname = imagenames[i].substr(0, imagenames[i].size()-1); @@ -107,11 +111,10 @@ int main(int argc,char** argv){ cerr<addTrainingSample(src, trainlandmarks[i]); } cout<<"Got data"<training(trainimages,Trainlandmarks,configfile_name,scale,modelfile_name); + facemark->training(); cout<<"Training complete"< facemark = FacemarkKazemi::create(params); + // std::vector scale(2, 460); + // facemark->setParams(cascade_name,modelfile_name,configfile_name,scale); facemark->setFaceDetector((FN_FaceDetector)myDetector, &face_cascade); std::vector images; std::vector > facePoints; loadTrainingData(imagesList, annotations, images, facePoints, 0.0); //gets landmarks and corresponding image names in both the vectors - vector Trainimages; - std::vector > Trainlandmarks; - //vector to store images Mat src; for(unsigned long i=0;iaddTrainingSample(src, facePoints[i]); } cout<<"Got data"<training(Trainimages,Trainlandmarks,configfile_name,scale,modelfile_name); + facemark->training(); cout<<"Training complete"< faces_; + defaultFaceDetector(image.getMat(), faces_); + Mat(faces_).copyTo(faces); + return true; + } return faceDetector(image, faces, faceDetectorData); } +bool FacemarkKazemiImpl::defaultFaceDetector(const Mat& image, std::vector& faces){ + Mat gray; + + faces.clear(); + + if (image.channels() > 1) + { + cvtColor(image, gray, COLOR_BGR2GRAY); + } + else + { + gray = image; + } + + equalizeHist(gray, gray); + + if (face_cascade.empty()) + { + { /* check the cascade classifier file */ + std::ifstream infile; + infile.open(params.faceCascadefile.c_str(), std::ios::in); + if (!infile) + CV_Error_(Error::StsBadArg, ("The cascade classifier model is not found: %s", params.faceCascadefile.c_str())); + } + face_cascade.load(params.faceCascadefile.c_str()); + CV_Assert(!face_cascade.empty()); + } + face_cascade.detectMultiScale(gray, faces, 1.05, 2, CASCADE_SCALE_IMAGE, Size(30, 30) ); + return true; +} +bool FacemarkKazemiImpl::getData(void * items){ + CV_UNUSED(items); + return false; +} +bool FacemarkKazemiImpl::addTrainingSample(InputArray image, std::vector & landmarks){ + std::vector & _landmarks = landmarks; + training_images.push_back(image.getMat()); + training_facePoints.push_back(_landmarks); + return true; +} +bool FacemarkKazemiImpl::setParams(const String& face_cascade_name,const String& facemark_model_name, const String& config_file_path, InputArray scale){ + if(face_cascade_name.empty() && facemark_model_name.empty() && config_file_path.empty() && scale.empty()) + { + CV_Error_(Error::StsBadArg, ("face cascade name, facemark model name, config file and scale all are empty")); + return false; + } + if(!face_cascade_name.empty()) + params.faceCascadefile = face_cascade_name; + if(!facemark_model_name.empty()) + params.modelfile = facemark_model_name; + if(!config_file_path.empty()) + params.configfile = config_file_path; + + Mat scale_mat = scale.getMat(); + std::vector _scale = scale_mat.reshape(1, scale_mat.rows); + if(_scale.size() != 2){ + CV_Error(Error::StsBadArg, "Please set the scale argument properly"); + return false; + } + params.scale = Size(_scale[0], _scale[1]); + CV_UNUSED(config_file_path); + return true; +} FacemarkKazemiImpl::FacemarkKazemiImpl(const FacemarkKazemi::Params& parameters) : faceDetector(NULL), faceDetectorData(NULL) @@ -45,6 +114,9 @@ FacemarkKazemi::Params::Params(){ //These variables are used for training data //These are initialised as described in the research paper //referenced above + configfile = ""; + modelfile = ""; + faceCascadefile = ""; cascade_depth = 15; tree_depth = 5; num_trees_per_cascade_level = 500; diff --git a/modules/face/src/face_alignmentimpl.hpp b/modules/face/src/face_alignmentimpl.hpp index 352e0f60bbd..f676ed82373 100644 --- a/modules/face/src/face_alignmentimpl.hpp +++ b/modules/face/src/face_alignmentimpl.hpp @@ -73,9 +73,12 @@ class FacemarkKazemiImpl : public FacemarkKazemi{ void loadModel(String fs) CV_OVERRIDE; bool setFaceDetector(FN_FaceDetector f, void* userdata) CV_OVERRIDE; bool getFaces(InputArray image, OutputArray faces) CV_OVERRIDE; + bool defaultFaceDetector(const Mat& image, std::vector& faces); + bool getData(void * items) CV_OVERRIDE; bool fit(InputArray image, InputArray faces, OutputArrayOfArrays landmarks ) CV_OVERRIDE; - void training(String imageList, String groundTruth); - bool training(vector& images, vector< vector >& landmarks,string filename,Size scale,string modelFilename) CV_OVERRIDE; + bool addTrainingSample(InputArray image, std::vector & landmarks) CV_OVERRIDE; + bool setParams(const String& face_cascade_name,const String& facemark_model_name, const String& config_file_path, InputArray scale) CV_OVERRIDE; + void training() CV_OVERRIDE; // Destructor for the class. virtual ~FacemarkKazemiImpl() CV_OVERRIDE; @@ -89,10 +92,14 @@ class FacemarkKazemiImpl : public FacemarkKazemi{ float minmeany; float maxmeany; bool isModelLoaded; + /* training data */ + std::vector training_images; + std::vector > training_facePoints; /* meanshape This is a vector which stores the mean shape of all the images used in training*/ std::vector meanshape; std::vector< std::vector > loaded_forests; std::vector< std::vector > loaded_pixel_coordinates; + CascadeClassifier face_cascade; FN_FaceDetector faceDetector; void* faceDetectorData; bool findNearestLandmarks(std::vector< std::vector >& nearest); diff --git a/modules/face/src/facemark.cpp b/modules/face/src/facemark.cpp index 26fbd07bc93..320b2e356f8 100644 --- a/modules/face/src/facemark.cpp +++ b/modules/face/src/facemark.cpp @@ -51,7 +51,7 @@ bool getFaces(InputArray image, OutputArray faces, CParams* params) return true; } -bool loadDatasetList(String imageList, String groundTruth, std::vector & images, std::vector & landmarks){ +bool loadDatasetList(String imageList, String groundTruth, CV_OUT std::vector & images, CV_OUT std::vector & landmarks){ std::string line; /*clear the output containers*/ @@ -215,8 +215,8 @@ bool getFacesHAAR(InputArray image, OutputArray faces, const String& face_cascad return true; } -bool loadTrainingData(vector filename,vector< vector > - & trainlandmarks,vector & trainimages) +bool loadTrainingData(vector filename, CV_OUT vector< vector > + & trainlandmarks, CV_OUT vector & trainimages) { string img; vector temp; diff --git a/modules/face/src/facemarkAAM.cpp b/modules/face/src/facemarkAAM.cpp index 5e1370e3f25..ad55c3dc4f0 100644 --- a/modules/face/src/facemarkAAM.cpp +++ b/modules/face/src/facemarkAAM.cpp @@ -36,6 +36,7 @@ Mentor: Delia Passalacqua #include "precomp.hpp" #include "opencv2/face.hpp" +#include namespace cv { namespace face { @@ -44,6 +45,7 @@ namespace face { */ FacemarkAAM::Params::Params(){ model_filename = ""; + cascade_filename = ""; m = 200; n = 10; n_iter = 50; @@ -66,7 +68,7 @@ void FacemarkAAM::Params::read( const cv::FileNode& fn ){ *this = FacemarkAAM::Params(); if (!fn["model_filename"].empty()) fn["model_filename"] >> model_filename; - + if (!fn["cascade_filename"].empty()) fn["cascade_filename"] >> cascade_filename; if (!fn["m"].empty()) fn["m"] >> m; if (!fn["n"].empty()) fn["n"] >> m; if (!fn["n_iter"].empty()) fn["n_iter"] >> m; @@ -79,6 +81,7 @@ void FacemarkAAM::Params::read( const cv::FileNode& fn ){ void FacemarkAAM::Params::write( cv::FileStorage& fs ) const{ fs << "model_filename" << model_filename; + fs << "cascade_filename" << cascade_filename; fs << "m" << m; fs << "n" << n; fs << "n_iter" << n_iter; @@ -110,8 +113,9 @@ class FacemarkAAMImpl : public FacemarkAAM { bool fit( InputArray image, InputArray faces, OutputArrayOfArrays landmarks ) CV_OVERRIDE; bool fitImpl( const Mat image, std::vector& landmarks,const Mat R,const Point2f T,const float scale, const int sclIdx=0 ); - bool addTrainingSample(InputArray image, InputArray landmarks) CV_OVERRIDE; - void training(void* parameters) CV_OVERRIDE; + bool addTrainingSample(InputArray image, std::vector & landmarks) CV_OVERRIDE; + bool setParams(const String& face_cascade_name,const String& facemark_model_name, const String& config_file_path, InputArray scale) CV_OVERRIDE; + void training() CV_OVERRIDE; Mat procrustes(std::vector , std::vector , Mat & , Scalar & , float & ); void calcMeanShape(std::vector > ,std::vector & ); @@ -141,6 +145,9 @@ class FacemarkAAMImpl : public FacemarkAAM { std::vector > facePoints; FacemarkAAM::Params params; FacemarkAAM::Model AAM; + + bool defaultFaceDetector(const Mat& image, std::vector& faces); + CascadeClassifier face_cascade; FN_FaceDetector faceDetector; void* faceDetectorData; @@ -188,10 +195,46 @@ bool FacemarkAAMImpl::setFaceDetector(bool(*f)(InputArray , OutputArray, void *) bool FacemarkAAMImpl::getFaces(InputArray image, OutputArray faces) { if (!faceDetector) - return false; + { + std::vector faces_; + defaultFaceDetector(image.getMat(), faces_); + Mat(faces_).copyTo(faces); + return true; + } return faceDetector(image, faces, faceDetectorData); } +bool FacemarkAAMImpl::defaultFaceDetector(const Mat& image, std::vector& faces){ + Mat gray; + + faces.clear(); + + if (image.channels() > 1) + { + cvtColor(image, gray, COLOR_BGR2GRAY); + } + else + { + gray = image; + } + + equalizeHist(gray, gray); + + if (face_cascade.empty()) + { + { /* check the cascade classifier file */ + std::ifstream infile; + infile.open(params.cascade_filename.c_str(), std::ios::in); + if (!infile) + CV_Error_(Error::StsBadArg, ("The cascade classifier model is not found: %s", params.cascade_filename.c_str())); + } + face_cascade.load(params.cascade_filename.c_str()); + CV_Assert(!face_cascade.empty()); + } + face_cascade.detectMultiScale(gray, faces, 1.4, 2, CASCADE_SCALE_IMAGE, Size(30, 30)); + return true; +} + bool FacemarkAAMImpl::getData(void * items){ CV_Assert(items); @@ -200,9 +243,8 @@ bool FacemarkAAMImpl::getData(void * items){ return true; } -bool FacemarkAAMImpl::addTrainingSample(InputArray image, InputArray landmarks){ - // FIXIT - std::vector & _landmarks = *(std::vector*)landmarks.getObj(); +bool FacemarkAAMImpl::addTrainingSample(InputArray image, std::vector & landmarks){ + std::vector & _landmarks = landmarks; images.push_back(image.getMat()); facePoints.push_back(_landmarks); @@ -210,8 +252,25 @@ bool FacemarkAAMImpl::addTrainingSample(InputArray image, InputArray landmarks){ return true; } -void FacemarkAAMImpl::training(void* parameters){ - if(parameters!=0){/*do nothing*/} +bool FacemarkAAMImpl::setParams(const String& face_cascade_name,const String& facemark_model_name, const String& config_file_path, InputArray scale){ + if(face_cascade_name.empty() && facemark_model_name.empty() && scale.empty()) + { + CV_Error_(Error::StsBadArg, ("face cascade name, facemark model name and scale all are empty")); + return false; + } + if(!face_cascade_name.empty()) + params.cascade_filename = face_cascade_name; + if(!facemark_model_name.empty()) + params.model_filename = facemark_model_name; + Mat scale_mat = scale.getMat(); + std::vector _scale = scale_mat.reshape(1, scale_mat.rows); + for(size_t i = 0; i < _scale.size(); i++) + params.scales.push_back(_scale[i]); + CV_UNUSED(config_file_path); + return true; +} + +void FacemarkAAMImpl::training(){ if (images.size()<1) { CV_Error(Error::StsBadArg, "Training data is not provided. Consider to add using addTrainingSample() function!"); } diff --git a/modules/face/src/facemarkLBF.cpp b/modules/face/src/facemarkLBF.cpp index 1181d718421..e09d99ef173 100644 --- a/modules/face/src/facemarkLBF.cpp +++ b/modules/face/src/facemarkLBF.cpp @@ -118,8 +118,9 @@ class FacemarkLBFImpl : public FacemarkLBF { bool fit(InputArray image, InputArray faces, OutputArrayOfArrays landmarks) CV_OVERRIDE; bool fitImpl( const Mat image, std::vector & landmarks );//!< from a face - bool addTrainingSample(InputArray image, InputArray landmarks) CV_OVERRIDE; - void training(void* parameters) CV_OVERRIDE; + bool addTrainingSample(InputArray image, std::vector & landmarks) CV_OVERRIDE; + bool setParams(const String& face_cascade_name,const String& facemark_model_name, const String& config_file_path, InputArray scale) CV_OVERRIDE; + void training() CV_OVERRIDE; Rect getBBox(Mat &img, const Mat_ shape); void prepareTrainingData(Mat img, std::vector facePoints, @@ -317,15 +318,29 @@ bool FacemarkLBFImpl::getData(void * items){ return false; } -bool FacemarkLBFImpl::addTrainingSample(InputArray image, InputArray landmarks){ +bool FacemarkLBFImpl::addTrainingSample(InputArray image, std::vector & landmarks){ // FIXIT - std::vector & _landmarks = *(std::vector*)landmarks.getObj(); + std::vector & _landmarks = landmarks; prepareTrainingData(image.getMat(), _landmarks, data_faces, data_shapes, data_boxes); return true; } -void FacemarkLBFImpl::training(void* parameters){ - CV_UNUSED(parameters); +bool FacemarkLBFImpl::setParams(const String& face_cascade_name, const String& facemark_model_name, const String& config_file_path, InputArray scale){ + if(face_cascade_name.empty() && facemark_model_name.empty()) + { + CV_Error_(Error::StsBadArg, ("Both the face cascade name and the facemark model name are empty")); + return false; + } + if(!face_cascade_name.empty()) + params.cascade_face = face_cascade_name; + if(!facemark_model_name.empty()) + params.model_filename = facemark_model_name; + CV_UNUSED(config_file_path); + CV_UNUSED(scale); + return true; +} + +void FacemarkLBFImpl::training(){ if (data_faces.empty()) { diff --git a/modules/face/src/trainFacemark.cpp b/modules/face/src/trainFacemark.cpp index 955df0d99ad..fd8f9902103 100644 --- a/modules/face/src/trainFacemark.cpp +++ b/modules/face/src/trainFacemark.cpp @@ -170,6 +170,7 @@ bool FacemarkKazemiImpl::getPixelIntensities(Mat img,vector pixel_coord vector FacemarkKazemiImpl::gradientBoosting(vector& samples,vector pixel_coordinates){ vector forest; vector meanresidual; + cout << samples[0].shapeResiduals.size() << endl; meanresidual.resize(samples[0].shapeResiduals.size()); for(unsigned long i=0;i& images, vector< vector >& landmarks,string filename,Size scale,string modelFilename){ - if(!setTrainingParameters(filename)){ +void FacemarkKazemiImpl::training(){ + if(!setTrainingParameters(params.configfile)){ String error_message = "Error while loading training parameters"; CV_Error(Error::StsBadArg, error_message); } + if (training_images.size()<1) { + CV_Error(Error::StsBadArg, "Training data is not provided. Consider to add using addTrainingSample() function!"); + } vector rectangles; - scaleData(landmarks,images,scale); - calcMeanShape(landmarks,images,rectangles); - if(images.size()!=landmarks.size()){ + scaleData(training_facePoints,training_images,params.scale); + calcMeanShape(training_facePoints,training_images,rectangles); + if(training_images.size()!=training_facePoints.size()){ // throw error if no data (or simply return -1?) String error_message = "The data is not loaded properly. Aborting training function...."; CV_Error(Error::StsBadArg, error_message); } vector samples; getTestCoordinates(); - createTrainingSamples(samples,images,landmarks,rectangles); - images.clear(); - landmarks.clear(); + createTrainingSamples(samples,training_images,training_facePoints,rectangles); + training_images.clear(); + training_facePoints.clear(); rectangles.clear(); for(unsigned long i=0;i< params.cascade_depth;i++){ cout<<"Training regressor "<& images, vector< vector > } loaded_forests.push_back(gradientBoosting(samples,loaded_pixel_coordinates[i])); } - saveModel(modelFilename); - return true; + saveModel(params.modelfile); + printf("Training is completed\n"); } }//cv }//face diff --git a/modules/face/test/test_face_align.cpp b/modules/face/test/test_face_align.cpp index 85419e34439..9a617191598 100644 --- a/modules/face/test/test_face_align.cpp +++ b/modules/face/test/test_face_align.cpp @@ -38,10 +38,15 @@ TEST(CV_Face_FacemarkKazemi, can_create_default) { TEST(CV_Face_FacemarkKazemi, can_loadTrainingData) { string filename = cvtest::findDataFile("face/lbpcascade_frontalface_improved.xml", true); string configfile_name = cvtest::findDataFile("face/config.xml", true); + string modelfilename = "face_landmark_model.dat"; + Size scale = Size(460,460); CascadeClassifier face_cascade; EXPECT_TRUE(face_cascade.load(filename)); FacemarkKazemi::Params params; params.configfile = configfile_name; + params.faceCascadefile = filename; + params.modelfile = modelfilename; + params.scale = scale; Ptr facemark; EXPECT_NO_THROW(facemark = FacemarkKazemi::create(params)); EXPECT_TRUE(facemark->setFaceDetector((cv::face::FN_FaceDetector)myDetector, &face_cascade)); @@ -51,21 +56,19 @@ TEST(CV_Face_FacemarkKazemi, can_loadTrainingData) { filename = cvtest::findDataFile("face/2.txt", true); filenames.push_back(filename); vector imagenames; - vector< vector > trainlandmarks,Trainlandmarks; + vector< vector > trainlandmarks; vector rectangles; //Test getData function EXPECT_NO_THROW(loadTrainingData(filenames,trainlandmarks,imagenames)); - vector trainimages; for(unsigned long i=0;iaddTrainingSample(src, trainlandmarks[i])); } - string modelfilename = "face_landmark_model.dat"; - Size scale = Size(460,460); - EXPECT_TRUE(facemark->training(trainimages,Trainlandmarks,configfile_name,scale,modelfilename)); + // std::vector scale(2, 460); + // EXPECT_TRUE(facemark->setParams(filename,modelfilename,configfile_name,scale)); + EXPECT_NO_THROW(facemark->training()); } TEST(CV_Face_FacemarkKazemi, can_detect_landmarks) { string cascade_name = cvtest::findDataFile("face/lbpcascade_frontalface_improved.xml", true); From bf79f4bc6b25710455132e525a3989287b2bd3f5 Mon Sep 17 00:00:00 2001 From: saiteja-talluri Date: Tue, 6 Aug 2019 20:34:21 +0530 Subject: [PATCH 2/2] Fixed windows build --- modules/face/src/face_alignment.cpp | 3 +-- modules/face/src/facemarkAAM.cpp | 1 - modules/face/src/facemarkLBF.cpp | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/face/src/face_alignment.cpp b/modules/face/src/face_alignment.cpp index 7f48b3a704f..6b55d089264 100644 --- a/modules/face/src/face_alignment.cpp +++ b/modules/face/src/face_alignment.cpp @@ -80,7 +80,6 @@ bool FacemarkKazemiImpl::setParams(const String& face_cascade_name,const String& if(face_cascade_name.empty() && facemark_model_name.empty() && config_file_path.empty() && scale.empty()) { CV_Error_(Error::StsBadArg, ("face cascade name, facemark model name, config file and scale all are empty")); - return false; } if(!face_cascade_name.empty()) params.faceCascadefile = face_cascade_name; @@ -90,7 +89,7 @@ bool FacemarkKazemiImpl::setParams(const String& face_cascade_name,const String& params.configfile = config_file_path; Mat scale_mat = scale.getMat(); - std::vector _scale = scale_mat.reshape(1, scale_mat.rows); + std::vector _scale = scale_mat.reshape(1, scale_mat.rows); if(_scale.size() != 2){ CV_Error(Error::StsBadArg, "Please set the scale argument properly"); return false; diff --git a/modules/face/src/facemarkAAM.cpp b/modules/face/src/facemarkAAM.cpp index ad55c3dc4f0..cd3dfd63241 100644 --- a/modules/face/src/facemarkAAM.cpp +++ b/modules/face/src/facemarkAAM.cpp @@ -256,7 +256,6 @@ bool FacemarkAAMImpl::setParams(const String& face_cascade_name,const String& fa if(face_cascade_name.empty() && facemark_model_name.empty() && scale.empty()) { CV_Error_(Error::StsBadArg, ("face cascade name, facemark model name and scale all are empty")); - return false; } if(!face_cascade_name.empty()) params.cascade_filename = face_cascade_name; diff --git a/modules/face/src/facemarkLBF.cpp b/modules/face/src/facemarkLBF.cpp index e09d99ef173..250e6bee3cf 100644 --- a/modules/face/src/facemarkLBF.cpp +++ b/modules/face/src/facemarkLBF.cpp @@ -329,7 +329,6 @@ bool FacemarkLBFImpl::setParams(const String& face_cascade_name, const String& f if(face_cascade_name.empty() && facemark_model_name.empty()) { CV_Error_(Error::StsBadArg, ("Both the face cascade name and the facemark model name are empty")); - return false; } if(!face_cascade_name.empty()) params.cascade_face = face_cascade_name;