1 /*
2 This file was part of GSoC Project: Facemark API for OpenCV
3 Final report: https://gist.github.com/kurnianggoro/74de9121e122ad0bd825176751d47ecc
4 Student: Laksono Kurnianggoro
5 Mentor: Delia Passalacqua
6 */
7
8 /*----------------------------------------------
9 * Usage:
10 * facemark_demo_lbf <face_cascade_model> <saved_model_filename> <training_images> <annotation_files> [test_files]
11 *
12 * Example:
13 * facemark_demo_lbf ../face_cascade.xml ../LBF.model ../images_train.txt ../points_train.txt ../test.txt
14 *
15 * Notes:
16 * the user should provides the list of training images_train
17 * accompanied by their corresponding landmarks location in separated files.
18 * example of contents for images_train.txt:
19 * ../trainset/image_0001.png
20 * ../trainset/image_0002.png
21 * example of contents for points_train.txt:
22 * ../trainset/image_0001.pts
23 * ../trainset/image_0002.pts
24 * where the image_xxxx.pts contains the position of each face landmark.
25 * example of the contents:
26 * version: 1
27 * n_points: 68
28 * {
29 * 115.167660 220.807529
30 * 116.164839 245.721357
31 * 120.208690 270.389841
32 * ...
33 * }
34 * example of the dataset is available at https://ibug.doc.ic.ac.uk/download/annotations/ibug.zip
35 *--------------------------------------------------*/
36
37 #include <stdio.h>
38 #include <fstream>
39 #include <sstream>
40 #include <iostream>
41 #include "opencv2/core.hpp"
42 #include "opencv2/highgui.hpp"
43 #include "opencv2/imgproc.hpp"
44 #include "opencv2/face.hpp"
45
46 using namespace std;
47 using namespace cv;
48 using namespace cv::face;
49
50 static bool myDetector( InputArray image, OutputArray roi, CascadeClassifier *face_detector);
51 static bool parseArguments(int argc, char** argv, String & cascade,
52 String & model, String & images, String & annotations, String & testImages
53 );
54
main(int argc,char ** argv)55 int main(int argc, char** argv)
56 {
57 String cascade_path,model_path,images_path, annotations_path, test_images_path;
58 if(!parseArguments(argc, argv, cascade_path,model_path,images_path, annotations_path, test_images_path))
59 return -1;
60
61 /*create the facemark instance*/
62 FacemarkLBF::Params params;
63 params.model_filename = model_path;
64 params.cascade_face = cascade_path;
65 Ptr<FacemarkLBF> facemark = FacemarkLBF::create(params);
66
67 CascadeClassifier face_cascade;
68 face_cascade.load(params.cascade_face.c_str());
69 facemark->setFaceDetector((FN_FaceDetector)myDetector, &face_cascade);
70
71 /*Loads the dataset*/
72 std::vector<String> images_train;
73 std::vector<String> landmarks_train;
74 loadDatasetList(images_path,annotations_path,images_train,landmarks_train);
75
76 Mat image;
77 std::vector<Point2f> facial_points;
78 for(size_t i=0;i<images_train.size();i++){
79 printf("%i/%i :: %s\n", (int)(i+1), (int)images_train.size(),images_train[i].c_str());
80 image = imread(images_train[i].c_str());
81 loadFacePoints(landmarks_train[i],facial_points);
82 facemark->addTrainingSample(image, facial_points);
83 }
84
85 /*train the Algorithm*/
86 facemark->training();
87
88 /*test using some images*/
89 String testFiles(images_path), testPts(annotations_path);
90 if(!test_images_path.empty()){
91 testFiles = test_images_path;
92 testPts = test_images_path; //unused
93 }
94 std::vector<String> images;
95 std::vector<String> facePoints;
96 loadDatasetList(testFiles, testPts, images, facePoints);
97
98 std::vector<Rect> rects;
99 CascadeClassifier cc(params.cascade_face.c_str());
100 for(size_t i=0;i<images.size();i++){
101 std::vector<std::vector<Point2f> > landmarks;
102 cout<<images[i];
103 Mat img = imread(images[i]);
104 facemark->getFaces(img, rects);
105 facemark->fit(img, rects, landmarks);
106
107 for(size_t j=0;j<rects.size();j++){
108 drawFacemarks(img, landmarks[j], Scalar(0,0,255));
109 rectangle(img, rects[j], Scalar(255,0,255));
110 }
111
112 if(rects.size()>0){
113 cout<<endl;
114 imshow("result", img);
115 waitKey(0);
116 }else{
117 cout<<"face not found"<<endl;
118 }
119 }
120 }
121
myDetector(InputArray image,OutputArray faces,CascadeClassifier * face_cascade)122 bool myDetector(InputArray image, OutputArray faces, CascadeClassifier *face_cascade)
123 {
124 Mat gray;
125
126 if (image.channels() > 1)
127 cvtColor(image, gray, COLOR_BGR2GRAY);
128 else
129 gray = image.getMat().clone();
130
131 equalizeHist(gray, gray);
132
133 std::vector<Rect> faces_;
134 face_cascade->detectMultiScale(gray, faces_, 1.4, 2, CASCADE_SCALE_IMAGE, Size(30, 30));
135 Mat(faces_).copyTo(faces);
136 return true;
137 }
138
parseArguments(int argc,char ** argv,String & cascade,String & model,String & images,String & annotations,String & test_images)139 bool parseArguments(int argc, char** argv,
140 String & cascade,
141 String & model,
142 String & images,
143 String & annotations,
144 String & test_images
145 ){
146 const String keys =
147 "{ @c cascade | | (required) path to the face cascade xml file fo the face detector }"
148 "{ @i images | | (required) path of a text file contains the list of paths to all training images}"
149 "{ @a annotations | | (required) Path of a text file contains the list of paths to all annotations files}"
150 "{ @m model | | (required) path to save the trained model }"
151 "{ t test-images | | Path of a text file contains the list of paths to the test images}"
152 "{ help h usage ? | | facemark_demo_lbf -cascade -images -annotations -model [-t] \n"
153 " example: facemark_demo_lbf ../face_cascade.xml ../images_train.txt ../points_train.txt ../lbf.model}"
154 ;
155 CommandLineParser parser(argc, argv,keys);
156 parser.about("hello");
157
158 if (parser.has("help")){
159 parser.printMessage();
160 return false;
161 }
162
163 cascade = String(parser.get<String>("cascade"));
164 model = String(parser.get<string>("model"));
165 images = String(parser.get<string>("images"));
166 annotations = String(parser.get<string>("annotations"));
167 test_images = String(parser.get<string>("t"));
168
169 cout<<"cascade : "<<cascade.c_str()<<endl;
170 cout<<"model : "<<model.c_str()<<endl;
171 cout<<"images : "<<images.c_str()<<endl;
172 cout<<"annotations : "<<annotations.c_str()<<endl;
173
174 if(cascade.empty() || model.empty() || images.empty() || annotations.empty()){
175 std::cerr << "one or more required arguments are not found" << '\n';
176
177 parser.printMessage();
178 return false;
179 }
180
181 return true;
182 }
183