Goals
In this tutorial will helps you to
- Create a Facemark object.
- Set a user defined face detector for the facemark algorithm
- Train the algorithm.
- Use the trained model to detect the facial landmarks from a given image.
Preparation
Before you continue with this tutorial, you should download the dataset of facial landmarks detection. We suggest you to download the helen dataset which can be retrieved at http://www.ifp.illinois.edu/~vuongle2/helen/ (Caution! The algorithm requires around 9GB of RAM to train on this dataset).
Make sure that the annotation format is supported by the API, the contents in annotation file should look like the following snippet:
version: 1
n_points: 68
{
212.716603 499.771793
230.232816 566.290071
...
}
The next thing to do is to make 2 text files containing the list of image files and annotation files respectively. Make sure that the order or image and annotation in both files are matched. Furthermore, it is advised to use absolute path instead of relative path. Example to make the file list in Linux machine
example of content in the images_train.txt
/home/user/helen/trainset/100032540_1.jpg
/home/user/helen/trainset/100040721_1.jpg
/home/user/helen/trainset/100040721_2.jpg
/home/user/helen/trainset/1002681492_1.jpg
example of content in the annotation_train.txt
/home/user/helen/trainset/100032540_1.pts
/home/user/helen/trainset/100040721_1.pts
/home/user/helen/trainset/100040721_2.pts
/home/user/helen/trainset/1002681492_1.pts
Creating the facemark object
FacemarkLBF::Params params;
params.model_filename = "helen.model";
Ptr<Facemark> facemark = FacemarkLBF::create(params);
Set a custom face detector function
Firstly, you need to create your own face detector function, you might also need to create a struct
to save the custom parameter. Alternatively, you can just make these parameter hard coded within the myDetector
function.
struct Conf {
double scaleFactor;
model_path = s;
scaleFactor = d;
face_detector.load(model_path);
};
CascadeClassifier face_detector;
};
Mat gray;
if (image.channels() > 1)
else
gray = image.getMat().clone();
std::vector<Rect> faces_;
Mat(faces_).copyTo(faces);
return true;
}
The following snippet demonstrates how to set the custom detector to the facemark object and use it to detect the faces. Keep in mind that some facemark object might use the face detector during the training process.
Conf config("../data/lbpcascade_frontalface.xml", 1.4);
facemark->setFaceDetector(myDetector, &config);
Here is the snippet for detecting face using the user defined face detector function.
Mat img =
imread(
"../data/himym3.jpg");
std::vector<cv::Rect> faces;
facemark->getFaces(img, faces, config);
for(int j=0;j<faces.size();j++){
}
Training a facemark object
- First of all, you need to set the training parameters
params.n_landmarks = 68;
params.initShape_n = 10;
params.stages_n=5;
params.tree_n=6;
params.tree_depth=5;
facemark = FacemarkLBF::create(params);
- And then, you need to load the file list from the dataset that you have prepared.
std::vector<String> images_train;
std::vector<String> landmarks_train;
loadDatasetList(
"images_train.txt",
"annotation_train.txt",images_train,landmarks_train);
- The next step is to add training samples into the facemark object.
Mat image;
std::vector<Point2f> facial_points;
for(size_t i=0;i<images_train.size();i++){
image =
imread(images_train[i].c_str());
facemark->addTrainingSample(image, facial_points);
}
- execute the training process
Use the trained model to detect the facial landmarks from a given image.
- Detect the faces
facemark->getFaces(img, faces, config);
- Perform the fitting process
std::vector<std::vector<Point2f> > landmarks;
facemark->fit(img, faces, landmarks);
- Display the result
for(int j=0;j<faces.size();j++){
}