目标
本教程将帮助您:
- 创建 Facemark 对象。
- 为 Facemark 算法设置用户自定义的人脸检测器。
- 训练算法。
- 使用训练好的模型从给定图像中检测人脸关键点。
准备工作
在继续本教程之前,您应该下载人脸关键点检测数据集。我们建议您下载 helen 数据集,可从 http://www.ifp.illinois.edu/~vuongle2/helen/ 获取(注意!该算法需要大约 9GB 的 RAM 来训练此数据集)。
确保注释格式受 API 支持,注释文件中的内容应如下所示:
version: 1
n_points: 68
{
212.716603 499.771793
230.232816 566.290071
...
}
接下来,创建两个文本文件,分别包含图像文件列表和注释文件列表。确保两个文件中图像和注释的顺序匹配。此外,建议使用绝对路径而不是相对路径。在 Linux 机器上创建文件列表的示例:
ls $PWD/trainset/*.jpg > images_train.txt
ls $PWD/trainset/*.pts > annotation_train.txt
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
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
创建 Facemark 对象
/*创建 Facemark 实例*/
FacemarkLBF::Params params;
params.model_filename = "helen.model"; // 训练好的模型将使用此文件名保存
Ptr<Facemark> facemark = FacemarkLBF::create(params);
设置自定义人脸检测函数
首先,您需要创建自己的自定义人脸检测函数,您可能还需要创建一个struct来保存自定义参数。或者,您可以将这些参数硬编码到myDetector函数中。
struct Conf {
cv::String model_path;
double scaleFactor;
Conf(cv::String s, double d){
model_path = s;
scaleFactor = d;
face_detector.load(model_path);
};
CascadeClassifier face_detector;
};
bool myDetector(InputArray image, OutputArray faces, Conf *conf){
Mat gray;
if (image.channels() > 1)
cvtColor(image, gray, COLOR_BGR2GRAY);
else
gray = image.getMat().clone();
equalizeHist(gray, gray);
std::vector<Rect> faces_;
conf->face_cascade.detectMultiScale(gray, faces_, conf->scaleFactor, 2, CASCADE_SCALE_IMAGE, Size(30, 30) );
Mat(faces_).copyTo(faces);
return true;
}
以下代码段演示了如何将自定义检测器设置为 Facemark 对象并使用它来检测人脸。请记住,某些 Facemark 对象可能会在训练过程中使用人脸检测器。
Conf config("../data/lbpcascade_frontalface.xml", 1.4);
facemark->setFaceDetector(myDetector, &config); // 我们必须保证“config”对象的正确生命周期
以下是使用用户定义的人脸检测函数检测人脸的代码段。
Mat img = imread("../data/himym3.jpg");
std::vector<cv::Rect> faces;
facemark->getFaces(img, faces, config);
for(int j=0;j<faces.size();j++){
cv::rectangle(img, faces[j], cv::Scalar(255,0,255));
}
imshow("result", img);
waitKey(0);
训练 Facemark 对象
- 首先,您需要设置训练参数:
params.n_landmarks = 68; // 关键点数量
params.initShape_n = 10; // 用于数据增强的倍数
params.stages_n=5; // 细化阶段数
params.tree_n=6; // 每个关键点的模型中的树的数量
params.tree_depth=5; // 决策树的深度
facemark = FacemarkLBF::create(params);
- 然后,您需要从准备好的数据集中加载文件列表。
std::vector<String> images_train;
std::vector<String> landmarks_train;
loadDatasetList("images_train.txt","annotation_train.txt",images_train,landmarks_train);
- 下一步是将训练样本添加到 Facemark 对象中。
Mat image;
std::vector<Point2f> facial_points;
for(size_t i=0;i<images_train.size();i++){
image = imread(images_train[i].c_str());
loadFacePoints(landmarks_train[i],facial_points);
facemark->addTrainingSample(image, facial_points);
}
- 执行训练过程:
/*训练算法*/
facemark->training();
使用训练好的模型从给定图像中检测人脸关键点。
- 首先,加载训练好的模型。您也可以从此链接下载预训练模型:https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml
facemark->loadModel(params.model_filename);
- 检测人脸
facemark->getFaces(img, faces, config);
- 执行拟合过程
std::vector<std::vector<Point2f> > landmarks;
facemark->fit(img, faces, landmarks);
- 显示结果
for(int j=0;j<faces.size();j++){
face::drawFacemarks(img, landmarks[j], Scalar(0,0,255));
}
imshow("result", img);
waitKey(0);