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