shape_predictor是一个工具,它接收包含某个对象的图像区域,并输出一组点位置,这些点位置定义了对象的姿态。这方面的经典例子是人脸姿态预测,即以人脸图像作为输入,并期望识别出重要面部特征点的位置,如嘴角、眼角、鼻尖等。例如,以下是dlib的68个面部特征点形状预测器对HELEN数据集中一张图像的输出:

要创建此对象的有用实例,您需要使用shape_predictor_trainer对象,通过一组训练图像来训练一个shape_predictor,每张图像都标注了您想要预测的形状。为此,shape_predictor_trainer采用了论文中的最先进方法:
Vahid Kazemi和Josephine Sullivan在2014年CVPR会议上提出的基于回归树集的毫秒级人脸对齐方法
C++示例程序:face_landmark_detection_ex.cpp、train_shape_predictor_ex.cpp、webcam_face_pose_ex.cpp
Python示例程序:train_shape_predictor.py、face_landmark_detection.py、face_alignment.py
Train_shape_predictor_ex.cpp (dlib-20.0\examples)
在这个例子中,我们将基于(某种数据或算法)训练一个形状预测器,位于examples/faces目录中的小脸数据集。所以首先我们要做的就是加载这个数据集。这意味着你需要提供将此faces文件夹的路径作为命令行参数,以便我们识别它的位置。
if (argc != 2)
{
cout << "Give the path to the examples/faces directory as the argument to this" << endl;
cout << "program. For example, if you are in the examples folder then execute " << endl;
cout << "this program by running: " << endl;
cout << " ./train_shape_predictor_ex faces" << endl;
cout << endl;
return 0;
}
const std::string faces_directory = argv[1];
faces目录包含一个训练数据集和一个单独的测试数据集。训练数据由4张图像组成,每张 用矩形框标出每个人脸,并标注68个特征点每个人脸上的面部特征点。我们的想法是利用这些训练数据学习识别新场景中人脸上的标志性位置图像。一旦你训练了一个shape_predictor,同样重要的是在未训练过的数据上测试它。因此,我们还将加载一个由5张图像组成的独立测试集。一旦我们有了根据训练数据创建的shape_predictor,我们将通过在测试图像上运行它来检验其效果如何。所以,我们在这里创建了用于存储数据集的变量。 images_train 将保存 4 张训练图像,而 faces_train 则保存训练图像中每张脸的位置和姿态。所以对于例如,图像 images_train[0] 包含由给定参数表示的脸部faces_train[0]中的full_object_detections。
dlib::array<array2d<unsigned char> > images_train, images_test;
std::vector<std::vector<full_object_detection> > faces_train, faces_test;
现在我们加载数据。这些XML文件列出了每个文件中的图像数据集,还包含面部框的位置和坐标(在XML文件中称为parts)。显然,你可以使用任何您喜欢的输入格式,只要您将数据存储到images_train和faces_train。但为了方便起见,dlib附带了用于创建和加载XML图像数据集文件的工具。看这里如何加载数据。要创建XML文件,可以使用imglab工具,可以在tools/imglab文件夹中找到。这都是用于标记图像中对象的图形工具。了解如何使用它请阅读tools/imglab/README.txt文件。
load_image_dataset(images_train, faces_train, faces_directory+"/training_with_face_landmarks.xml");
load_image_dataset(images_test, faces_test, faces_directory+"/testing_with_face_landmarks.xml");
现在让对象负责训练模型。
shape_predictor_trainer trainer;
这个算法有一堆你可以弄乱的参数。shapepredictor_trainer的文档解释了所有这些参数。您还应该阅读Kazemi的论文,其中非常详细地解释了所有参数。然而,在这里,我只设置了其中的三个与默认值不同。我这样做是因为我们有一个非常小的数据集。特别是,如果设置过采样训练量很大(300),则有效地增加了训练集的大小。
trainer.set_oversampling_amount(300);
我还通过显式增加regularization(使nu变小)来降低模型的容量和使用较小的树深度。
trainer.set_nu(0.05);
trainer.set_tree_depth(2);
训练过程的某些部分可以并行,可能的话训练应使用此线程数
trainer.set_num_threads(2);
告诉训练将状态消息打印到控制台,以便我们可以看看训练需要多长时间。
trainer.be_verbose();
最后生成形状模型
shape_predictor sp = trainer.train(images_train, faces_train);
现在我们有了一个模型,我们可以对其进行测试。此函数用于测量由shape_predictor输出的面部坐标之间的平均距离,以及根据真实数据应该在哪里。请注意,有一个可选的第四个参数可以让我们重新缩放距离。在这里,我们使输出按比例缩放每个人脸的按瞳孔间距计算距离,这在评估面部方位(landmark)系统时是惯例(customary)。
cout << "mean training error: "<<
test_shape_predictor(sp, images_train, faces_train, get_interocular_distances(faces_train)) << endl;
实际的测试是看它在未经训练的数据上表现如何。我们在一个非常小的数据集上训练了它,所以精度不是非常高,但仍然做得很好。此外,如果你在你将要使用的大型人脸标记数据集上训练它如Kazemi论文所示,获得当前最高水平的结果(state-of-the-art results)。
cout << "mean testing error: "<<
test_shape_predictor(sp, images_test, faces_test, get_interocular_distances(faces_test)) << endl;
最后,我们把结果保存,以便将来使用
serialize("sp.dat") << sp;
3806

被折叠的 条评论
为什么被折叠?



