目标
本教程将帮助您:
- 创建一个 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
...
}
接下来要做的是创建 2 个文本文件,分别包含图像文件和注释文件的列表。确保两个文件中图像和注释的顺序匹配。此外,建议使用绝对路径而不是相对路径。在 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);