1
2 /*
3
4 This is the program that created the http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2 model file.
5
6 */
7
8
9 #include <dlib/image_processing/frontal_face_detector.h>
10 #include <dlib/image_processing.h>
11 #include <dlib/console_progress_indicator.h>
12 #include <dlib/data_io.h>
13 #include <dlib/statistics.h>
14 #include <iostream>
15
16 using namespace dlib;
17 using namespace std;
18
19 // ----------------------------------------------------------------------------------------
20
21 std::vector<std::vector<double> > get_interocular_distances (
22 const std::vector<std::vector<full_object_detection> >& objects
23 );
24 /*!
25 ensures
26 - returns an object D such that:
27 - D[i][j] == the distance, in pixels, between the eyes for the face represented
28 by objects[i][j].
29 !*/
30
31 // ----------------------------------------------------------------------------------------
32
33 template <
34 typename image_array_type,
35 typename T
36 >
add_image_left_right_flips_5points(image_array_type & images,std::vector<std::vector<T>> & objects)37 void add_image_left_right_flips_5points (
38 image_array_type& images,
39 std::vector<std::vector<T> >& objects
40 )
41 {
42 // make sure requires clause is not broken
43 DLIB_ASSERT( images.size() == objects.size(),
44 "\t void add_image_left_right_flips()"
45 << "\n\t Invalid inputs were given to this function."
46 << "\n\t images.size(): " << images.size()
47 << "\n\t objects.size(): " << objects.size()
48 );
49
50 typename image_array_type::value_type temp;
51 std::vector<T> rects;
52
53 const unsigned long num = images.size();
54 for (unsigned long j = 0; j < num; ++j)
55 {
56 const point_transform_affine tran = flip_image_left_right(images[j], temp);
57
58 rects.clear();
59 for (unsigned long i = 0; i < objects[j].size(); ++i)
60 {
61 rects.push_back(impl::tform_object(tran, objects[j][i]));
62
63 DLIB_CASSERT(rects.back().num_parts() == 5);
64 swap(rects.back().part(0), rects.back().part(2));
65 swap(rects.back().part(1), rects.back().part(3));
66 }
67
68 images.push_back(temp);
69 objects.push_back(rects);
70 }
71 }
72
73 // ----------------------------------------------------------------------------------------
74
main(int argc,char ** argv)75 int main(int argc, char** argv)
76 {
77 try
78 {
79 if (argc != 2)
80 {
81 cout << "give the path to the training data folder" << endl;
82 return 0;
83 }
84 const std::string faces_directory = argv[1];
85 dlib::array<array2d<unsigned char> > images_train, images_test;
86 std::vector<std::vector<full_object_detection> > faces_train, faces_test;
87
88 std::vector<std::string> parts_list;
89 load_image_dataset(images_train, faces_train, faces_directory+"/train_cleaned.xml", parts_list);
90 load_image_dataset(images_test, faces_test, faces_directory+"/test_cleaned.xml");
91
92 add_image_left_right_flips_5points(images_train, faces_train);
93 add_image_left_right_flips_5points(images_test, faces_test);
94 add_image_rotations(linspace(-20,20,3)*pi/180.0,images_train, faces_train);
95
96 cout << "num training images: "<< images_train.size() << endl;
97
98 for (auto& part : parts_list)
99 cout << part << endl;
100
101 shape_predictor_trainer trainer;
102 trainer.set_oversampling_amount(40);
103 trainer.set_num_test_splits(150);
104 trainer.set_feature_pool_size(800);
105 trainer.set_num_threads(4);
106 trainer.set_cascade_depth(15);
107 trainer.be_verbose();
108
109 // Now finally generate the shape model
110 shape_predictor sp = trainer.train(images_train, faces_train);
111
112 serialize("shape_predictor_5_face_landmarks.dat") << sp;
113
114 cout << "mean training error: "<<
115 test_shape_predictor(sp, images_train, faces_train, get_interocular_distances(faces_train)) << endl;
116
117 cout << "mean testing error: "<<
118 test_shape_predictor(sp, images_test, faces_test, get_interocular_distances(faces_test)) << endl;
119
120 }
121 catch (exception& e)
122 {
123 cout << "\nexception thrown!" << endl;
124 cout << e.what() << endl;
125 }
126 }
127
128 // ----------------------------------------------------------------------------------------
129
interocular_distance(const full_object_detection & det)130 double interocular_distance (
131 const full_object_detection& det
132 )
133 {
134 dlib::vector<double,2> l, r;
135 // left eye
136 l = (det.part(0) + det.part(1))/2;
137 // right eye
138 r = (det.part(2) + det.part(3))/2;
139
140 return length(l-r);
141 }
142
get_interocular_distances(const std::vector<std::vector<full_object_detection>> & objects)143 std::vector<std::vector<double> > get_interocular_distances (
144 const std::vector<std::vector<full_object_detection> >& objects
145 )
146 {
147 std::vector<std::vector<double> > temp(objects.size());
148 for (unsigned long i = 0; i < objects.size(); ++i)
149 {
150 for (unsigned long j = 0; j < objects[i].size(); ++j)
151 {
152 temp[i].push_back(interocular_distance(objects[i][j]));
153 }
154 }
155 return temp;
156 }
157
158 // ----------------------------------------------------------------------------------------
159
160