Skip to content

Commit

Permalink
Custom parameters for default detector, training, and get custom data
Browse files Browse the repository at this point in the history
  • Loading branch information
kurnianggoro committed Sep 1, 2017
1 parent c0308d7 commit e284e30
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 37 deletions.
2 changes: 1 addition & 1 deletion modules/face/include/opencv2/face.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ the use of this software, even if advised of the possibility of such damage.
#define __OPENCV_FACE_HPP__

/**
@defgroup face Face Recognition
@defgroup face Face Analysis
- @ref face_changelog
- @ref tutorial_face_main
Expand Down
56 changes: 41 additions & 15 deletions modules/face/include/opencv2/face/facemark.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ Mentor: Delia Passalacqua
#define __OPENCV_FACELANDMARK_HPP__

/**
@defgroup face Face Recognition
@defgroup face Face Analysis
- @ref tutorial_table_of_content_facemark
- The Facemark API
*/

#include "opencv2/face.hpp"
Expand All @@ -52,7 +53,21 @@ namespace face {

//! @addtogroup face
//! @{

struct CV_EXPORTS_W CParams{
String cascade; //!< the face detector
double scaleFactor; //!< Parameter specifying how much the image size is reduced at each image scale.
int minNeighbors; //!< Parameter specifying how many neighbors each candidate rectangle should have to retain it.
Size minSize; //!< Minimum possible object size.
Size maxSize; //!< Maximum possible object size.

CParams(
String cascade_model,
double sf = 1.1,
int minN = 3,
Size minSz = Size(30, 30),
Size maxSz = Size()
);
};
/** @brief Default face detector
This function is mainly utilized by the implementation of a Facemark Algorithm.
End users are advised to use function Facemark::getFaces which can be manually defined
Expand All @@ -61,12 +76,7 @@ namespace face {
@param image The input image to be processed.
@param faces Output of the function which represent region of interest of the detected faces.
Each face is stored in cv::Rect container.
@param face_cascade_path The path to a cascade model for face detection.
@param scaleFactor Parameter specifying how much the image size is reduced at each image scale.
@param minNeighbors Parameter Parameter specifying how many neighbors each candidate rectangle should have to retain it.
@param minSize Minimum possible object size.
@param maxSize Maximum possible object size.
@param extra_params extra parameters
<B>Example of usage</B>
@code
std::vector<cv::Rect> roi;
Expand All @@ -78,13 +88,10 @@ namespace face {
cv::imshow("detection", frame);
@endcode
*/
CV_EXPORTS_W bool getFaces( InputArray image,
/*other option: move this function inside Facemark as default face detector*/
CV_EXPORTS bool getFaces( InputArray image,
OutputArray faces,
String face_cascade_path,
double scaleFactor=1.1,
int minNeighbors=3,
Size minSize=Size(30, 30),
Size maxSize=Size()
void * extra_params
);

/** @brief A utility to load list of paths to training image and annotation file.
Expand Down Expand Up @@ -314,6 +321,8 @@ namespace face {
Before the training process, training samples should be added to the trainer
using face::addTrainingSample function.
@param parameters Optional extra parameters (algorithm dependent).
<B>Example of usage</B>
@code
FacemarkLBF::Params params;
Expand All @@ -326,7 +335,7 @@ namespace face {
@endcode
*/

virtual void training()=0;
virtual void training(void* parameters=0)=0;

/** @brief A function to load the trained model before the fitting process.
Expand Down Expand Up @@ -401,6 +410,23 @@ namespace face {
*/
virtual bool getFaces( InputArray image , OutputArray faces, void * extra_params=0)=0;

/** @brief Get data from an algorithm
@param items The obtained data, algorithm dependent.
<B>Example of usage</B>
@code
Ptr<FacemarkAAM> facemark = FacemarkAAM::create();
facemark->loadModel("AAM.yml");
FacemarkAAM::Data data;
facemark->getData(&data);
std::vector<Point2f> s0 = data.s0;
cout<<s0<<endl;
@endcode
*/
virtual bool getData(void * items=0)=0;
}; /* Facemark*/

//! @}
Expand Down
11 changes: 11 additions & 0 deletions modules/face/include/opencv2/face/facemarkAAM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ namespace face {
bool verbose;
};

/**
* \brief Optional parameter for fitting process.
*/
struct CV_EXPORTS Config
{
Config( Mat rot = Mat::eye(2,2,CV_32F),
Expand All @@ -84,6 +87,14 @@ namespace face {

};

/**
* \brief Data container for the facemark::getData function
*/
struct CV_EXPORTS Data
{
std::vector<Point2f> s0;
};

/**
* \brief The model of AAM Algorithm
*/
Expand Down
6 changes: 3 additions & 3 deletions modules/face/samples/facemark_demo_aam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ Mentor: Delia Passalacqua
Point2f T;
Mat R;

FacemarkAAM::Model config;
facemark->getParams(config);
std::vector<Point2f> s0 = config.s0;
FacemarkAAM::Data data;
facemark->getData(&data);
std::vector<Point2f> s0 = data.s0;

/*fitting process*/
std::vector<Rect> faces;
Expand Down
4 changes: 2 additions & 2 deletions modules/face/samples/facemark_lbf_fitting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ bool parseArguments(int argc, char** argv, CommandLineParser & parser,
){
const String keys =
"{ @c cascade | | (required) path to the cascade model file for the face detector }"
"{ @m model | | (required) path to the cascade model file for the eyes detector }"
"{ @v video | | (required) path of a text file contains the list of paths to all training images}"
"{ @m model | | (required) path to the trained model }"
"{ @v video | | (required) path input video}"
"{ help h usage ? | | facemark_demo_aam -cascade -model -video [-t]\n"
" example: facemark_lbf_fitting ../face_cascade.xml ../LBF.model ../video.mp4}"
;
Expand Down
31 changes: 21 additions & 10 deletions modules/face/src/facemark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,33 @@ Mentor: Delia Passalacqua

namespace cv {
namespace face {
CParams::CParams(String s, double sf, int minN, Size minSz, Size maxSz){
cascade = s;
scaleFactor = sf;
minNeighbors = minN;
minSize = minSz;
maxSize = maxSz;
}

bool getFaces(InputArray image, OutputArray faces, String face_cascade_path,
double scale, int minNeighbors, Size minSz, Size maxSz
){
bool getFaces(InputArray image, OutputArray faces, void * parameters){
Mat gray;
std::vector<Rect> roi;

cvtColor( image.getMat(), gray, CV_BGR2GRAY );
equalizeHist( gray, gray );
if(parameters!=0){
CParams * params = (CParams *)parameters;
cvtColor( image.getMat(), gray, CV_BGR2GRAY );
equalizeHist( gray, gray );

CascadeClassifier face_cascade;
if( !face_cascade.load( face_cascade_path ) ){ printf("--(!)Error loading face_cascade\n"); return false; };
face_cascade.detectMultiScale( gray, roi, scale, minNeighbors, 0|CV_HAAR_SCALE_IMAGE, minSz, maxSz);
CascadeClassifier face_cascade;
if( !face_cascade.load( params->cascade ) ){ printf("--(!)Error loading face_cascade\n"); return false; };
face_cascade.detectMultiScale( gray, roi, params->scaleFactor, params->minNeighbors, 0|CV_HAAR_SCALE_IMAGE, params->minSize, params->maxSize);

Mat(roi).copyTo(faces);
return true;
}else{
return false;
}

Mat(roi).copyTo(faces);
return true;
}

bool loadDatasetList(String imageList, String groundTruth, std::vector<String> & images, std::vector<String> & landmarks){
Expand Down
18 changes: 16 additions & 2 deletions modules/face/src/facemarkAAM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,16 @@ namespace face {
bool getFaces( InputArray image ,OutputArray faces, void * extra_params);
void getParams(Model & params);

bool getData(void * items);

protected:

bool fit( InputArray image, InputArray faces, InputOutputArray landmarks, void * runtime_params);//!< from many ROIs
bool fitSingle( InputArray image, OutputArray landmarks, Mat R, Point2f T, float scale );
bool fitImpl( const Mat image, std::vector<Point2f>& landmarks,const Mat R,const Point2f T,const float scale );

bool addTrainingSample(InputArray image, InputArray landmarks);
void training();
void training(void* parameters);

Mat procrustes(std::vector<Point2f> , std::vector<Point2f> , Mat & , Scalar & , float & );
void calcMeanShape(std::vector<std::vector<Point2f> > ,std::vector<Point2f> & );
Expand Down Expand Up @@ -184,6 +186,17 @@ namespace face {
return true;
}

bool FacemarkAAMImpl::getData(void * items){
if(items==0){
return true;
}else{
Data * data = (Data*)items;
data->s0 = AAM.s0;
return true;
}
return false;
}

bool FacemarkAAMImpl::addTrainingSample(InputArray image, InputArray landmarks){
std::vector<Point2f> & _landmarks = *(std::vector<Point2f>*)landmarks.getObj();

Expand All @@ -193,7 +206,8 @@ namespace face {
return true;
}

void FacemarkAAMImpl::training(){
void FacemarkAAMImpl::training(void* parameters){
if(parameters!=0){/*do nothing*/}
if (images.size()<1) {
std::string error_message =
"Training data is not provided. Consider to add using addTrainingSample() function!";
Expand Down
13 changes: 11 additions & 2 deletions modules/face/src/facemarkLBF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ namespace face {

bool setFaceDetector(bool(*f)(InputArray , OutputArray, void * extra_params ));
bool getFaces( InputArray image , OutputArray faces, void * extra_params);
bool getData(void * items);

Params params;

Expand All @@ -118,7 +119,7 @@ namespace face {
bool fitImpl( const Mat image, std::vector<Point2f> & landmarks );//!< from a face

bool addTrainingSample(InputArray image, InputArray landmarks);
void training();
void training(void* parameters);

Rect getBBox(Mat &img, const Mat_<double> shape);
void prepareTrainingData(Mat img, std::vector<Point2f> facePoints,
Expand Down Expand Up @@ -299,14 +300,22 @@ namespace face {
return true;
}

bool FacemarkLBFImpl::getData(void * items){
if(items!=0){
// do nothing
}
return true;
}

bool FacemarkLBFImpl::addTrainingSample(InputArray image, InputArray landmarks){
std::vector<Point2f> & _landmarks = *(std::vector<Point2f>*)landmarks.getObj();
configFaceDetector();
prepareTrainingData(image.getMat(), _landmarks, data_faces, data_shapes, data_boxes);
return true;
}

void FacemarkLBFImpl::training(){
void FacemarkLBFImpl::training(void* parameters){
if(parameters!=0){/*do nothing*/}
if (data_faces.size()<1) {
std::string error_message =
"Training data is not provided. Consider to add using addTrainingSample() function!";
Expand Down
3 changes: 2 additions & 1 deletion modules/face/test/test_facemark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ TEST(CV_Face_Facemark, test_utilities) {
Mat img = imread(image_file);
EXPECT_NO_THROW(drawFacemarks(img, facial_points, Scalar(0,0,255)));

CParams * params = new CParams(cascade_filename);
std::vector<Rect> faces;
EXPECT_TRUE(getFaces(img, faces, cascade_filename));
EXPECT_TRUE(getFaces(img, faces, params));
}
13 changes: 13 additions & 0 deletions modules/face/test/test_facemark_aam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,16 @@ TEST(CV_Face_FacemarkAAM, can_detect_landmarks) {
EXPECT_TRUE(facemark->fit(image, rects, landmarks));
EXPECT_TRUE(landmarks[0].size()>0);
}

TEST(CV_Face_FacemarkAAM, get_data) {
FacemarkAAM::Params params;
params.verbose = false;
Ptr<Facemark> facemark = FacemarkAAM::create(params);

string model_filename = "AAM.yml";
EXPECT_NO_THROW(facemark->loadModel(model_filename.c_str()));

FacemarkAAM::Data data;
EXPECT_TRUE(facemark->getData(&data));
EXPECT_TRUE(data.s0.size()>0);
}
5 changes: 5 additions & 0 deletions modules/face/test/test_facemark_lbf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,8 @@ TEST(CV_Face_FacemarkLBF, can_detect_landmarks) {
EXPECT_TRUE(facemark->fit(image, rects, landmarks));
EXPECT_TRUE(landmarks[0].size()>0);
}

TEST(CV_Face_FacemarkLBF, get_data) {
Ptr<Facemark> facemark = FacemarkLBF::create();
EXPECT_TRUE(facemark->getData());
}
2 changes: 1 addition & 1 deletion modules/face/tutorials/facemark_tutorial.markdown
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Facial Landmark Detector API {#tutorial_table_of_content_facemark}
Tutorial on Facial Landmark Detector API {#tutorial_table_of_content_facemark}
==========================================================

The facial landmark detector API is useful to detect facial landmarks from an input image.
Expand Down

0 comments on commit e284e30

Please sign in to comment.