faceExtract.cc
1 const char *help = "\
2 progname: faceExtract.cc\n\
3 code2html: This program reads an image and an annotation file and extracts faces.\n\
4 version: Torch3 vision2.0, 2003-2005\n\
5 (c) Yann Rodriguez (rodrig@idiap.ch) and Sebastien Marcel (marcel@idiap.ch)\n";
6
7 #include "Image.h"
8 #include "ImageGray.h"
9 #include "ImageRgb.h"
10 #include "ImageDiskXFile.h"
11 #include "xtprobeImageDiskXFile.h"
12 #include "FaceModel.h"
13 #include "FrontalFace15x20.h"
14 #include "FrontalFace19x19.h"
15 #include "NonFrontalFace19x19.h"
16 #include "FrontalFace64x80.h"
17 #include "FrontalFace64x40.h"
18 #include "FrontalFace64x56.h"
19 #include "ipFaceExtract.h"
20 #include "Random.h"
21 #include "CmdLine.h"
22 #include "DiskXFile.h"
23
24 using namespace Torch;
25
26 int main(int argc, char *argv[])
27 {
28 char *imagefilename;
29 char *posfilename;
30
31 int facemodel_id;
32 int postype;
33 bool oneface;
34 int pan;
35
36 int shift;
37 int scale;
38 int rotate;
39 int n_selected;
40 real angle_offset;
41
42 int width_out;
43 int height_out;
44
45 bool savepgm;
46 char *bin_filename;
47 bool verbose;
48 bool draw;
49 bool norm;
50
51
52 CmdLine cmd;
53 cmd.setBOption("write log", false);
54 cmd.info(help);
55
56 cmd.addText("\nArguments:");
57 cmd.addSCmdArg("imagefile", &imagefilename, "image file");
58 cmd.addSCmdArg("posfile", &posfilename, "pos file");
59
60 cmd.addText("\nOptions:");
61 cmd.addICmdOption("-facemodel", &facemodel_id, 2, "facemodel (1=15x20, 2=19x19, 3=64x80, 4=64x40, 5=64x56)");
62 cmd.addICmdOption("-postype", &postype, 2, "posfile format (1=eyes center, 2=banca format, 3=eyes corners, 4=eye corners + nose tip + chin, 5=left eye corners + right eye center + nose tip + chin, 6=left eye center + nose tip + chin, 68=AAM's markup 68 pts)");
63 cmd.addBCmdOption("-oneface", &oneface, false, "only one face in the posfile (no header)");
64 cmd.addICmdOption("-pan", &pan, 0, "pan angle for non-frontal faces");
65
66 cmd.addRCmdOption("-angleoffset", &angle_offset, 0.0, "angle offset");
67 cmd.addICmdOption("-shift", &shift, 0, "number of shifts in pixels");
68 cmd.addICmdOption("-scale", &scale, 0, "number of scale levels");
69 cmd.addICmdOption("-rotate", &rotate, 0, "number of rotations");
70 cmd.addICmdOption("-select", &n_selected, 1, "number of patterns selected");
71
72 cmd.addICmdOption("-width", &width_out, -1, "width");
73 cmd.addICmdOption("-height", &height_out, -1, "height");
74
75 cmd.addBCmdOption("-savepgm", &savepgm, false, "save the cropped images in pgm");
76 cmd.addSCmdOption("-savebin", &bin_filename, "", "bin filename (Torch3 binary format)");
77 cmd.addBCmdOption("-verbose", &verbose, false, "print some information (mainly for debug)");
78 cmd.addBCmdOption("-draw", &draw, false, "draw");
79 cmd.addBCmdOption("-norm", &norm, false, "norm output values to [0,1]");
80
81 cmd.read(argc, argv);
82
83 Allocator *allocator = new Allocator;
84 Random::seed();
85
86 if(width_out == -1 || height_out == -1)
87 {
88 if(height_out != width_out) error("incorrect values for width or height.");
89 }
90
91
92 /*----------- 1] the .pos file -----------*/
93 DiskXFile pos_file(posfilename, "r");
94 int n_faces = 0;
95
96 if(oneface)
97 {
98 n_faces = 1;
99 if(verbose) message("1 face in the posfile (one face)");
100 }
101 else
102 {
103 pos_file.scanf("%d", &n_faces);
104 if(verbose) message("%d faces in the posfile", n_faces);
105 if(n_faces <=0 ) error("Incorrect value for n_faces. Exit.");
106 }
107
108
109 /*----------- 2] load the image -----------*/
110 Image *image;
111 ImageDiskXFile *image_disk;
112
113 image_disk = new(allocator) xtprobeImageDiskXFile(imagefilename, "r");
114 image = new(allocator) ImageGray(); // convert in gray if needed
115 image->loadImageXFile(image_disk);
116 allocator->free(image_disk);
117
118
119 /*----------- 3] the FaceModel -----------*/
120 FaceModel *face_model = NULL;
121
122 switch(facemodel_id)
123 {
124 case 1: if(verbose) message("using 15x20 face model.");
125
126 if(pan == 0) face_model = new(allocator) FrontalFace15x20(postype);
127 else error("No 15x20 non-frontal model available.");
128
129 break;
130
131 case 2: if(verbose) message("using 19x19 face model.");
132
133 if(pan == 0) face_model = new(allocator) FrontalFace19x19(postype);
134 else face_model = new(allocator) NonFrontalFace19x19(pan, postype);
135
136 break;
137
138 case 3: if(verbose) message("using 64x80 face model.");
139
140 if(pan == 0) face_model = new(allocator) FrontalFace64x80(postype);
141 else error("No 64x80 non-frontal model available.");
142
143 break;
144
145 case 4: if(verbose) message("using 64x40 face model.");
146
147 if(pan == 0) face_model = new(allocator) FrontalFace64x40(postype);
148 else error("No 64x40 non-frontal model available.");
149
150 break;
151
152 case 5: if(verbose) message("using 64x56 face model.");
153
154 if(pan == 0) face_model = new(allocator) FrontalFace64x56(postype);
155 else error("No 64x56 non-frontal model available.");
156
157 break;
158
159 default: error("Invalid face model. Exit.");
160 }
161
162 face_model->setBOption("verbose", verbose);
163 if(postype == 1)
164 {
165 if(verbose) message("reading eye centers pos format.");
166 }
167 else if(postype == 2)
168 {
169 if(verbose) message("reading Banca pos format.");
170 if(n_faces != 1) error("This postype is not defined for multiple face images.");
171 }
172 else if(postype == 3)
173 {
174 if(verbose) message("reading eye corners pos format.");
175 }
176 else if(postype == 4)
177 {
178 if(verbose) message("reading eye corners + nose tip + chin pos format (non frontal 22.5 degree).");
179 }
180 else if(postype == 5)
181 {
182 if(verbose) message("reading left eye corners + right eye center + nose tip + chin pos format (non frontal 45/67.5 degree).");
183 }
184 else if(postype == 6)
185 {
186 if(verbose) message("reading left eye center + nose tip + chin pos format (non frontal 90 degree).");
187 }
188 else if(postype == 68)
189 {
190 if(verbose) message("reading Tim Cootes Markup point format.");
191 }
192 else error("Invalid format for pos files. Exit.");
193
194 if(width_out == -1 || height_out == -1)
195 {
196 width_out = (int) face_model->model_width;
197 height_out = (int) face_model->model_height;
198 }
199
200 if(verbose) print("Output size: %dx%d\n", width_out, height_out);
201
202 /*----------- 4] the FaceExtractPIM's -----------*/
203 ipFaceExtract **face_extract = (ipFaceExtract **)allocator->alloc(n_faces*sizeof(ipFaceExtract *));
204
205 /*----------- 5] loop on all faces -----------*/
206 ImageRgb *colorimage = NULL;
207
208 if(draw)
209 {
210 colorimage = new(allocator) ImageRgb();
211 colorimage->copyFrom(image);
212 }
213
214 for(int i=0 ; i<n_faces; i++)
215 {
216 if(verbose) message("Face %d:", i+1);
217
218 face_model->loadXFile(&pos_file);
219
220 if(draw)
221 face_model->drawLDM(colorimage);
222
223 face_extract[i] = new(allocator) ipFaceExtract(image->width, image->height, width_out, height_out, image->coding, face_model, angle_offset, shift, scale, rotate, n_selected);
224 face_extract[i]->setBOption("verbose", verbose);
225
226 // extract the subimages
227 face_extract[i]->process(image);
228
229 }
230
231 if(draw)
232 colorimage->save("output.ppm");
233
234 /*----------- 5] gestion de: bindata_filename, savepgm .. -----------*/
235 // save the cropped images in pgm.
236 if(savepgm)
237 {
238 char filename[100];
239 ImageGray *image_out = new ImageGray();
240
241 for(int i=0; i<n_faces; i++)
242 {
243 for(int j=0; j<n_selected; j++)
244 {
245 image_out->copyFrom(width_out, height_out, face_extract[i]->seq_out->frames[j], face_extract[i]->coding);
246
247 sprintf(filename, "crop_%d_%d.pgm", i, j);
248 image_out->save(filename);
249 }
250 }
251 delete image_out;
252 }
253
254
255 // save the cropped images in a file (binary format).
256 if(strcmp(bin_filename, ""))
257 {
258 // each ipFaceExtract has the same #n_output# and #output_size#
259 // and remember that: face_extract[0]->n_output == n_selected ...
260 int output_size = face_extract[0]->seq_out->frame_size;
261 int n_output = face_extract[0]->seq_out->n_frames * n_faces;
262
263 DiskXFile bin_file = DiskXFile(bin_filename, "w");
264
265 bin_file.write(&n_output, sizeof(int), 1);
266 bin_file.write(&output_size, sizeof(int), 1);
267
268
269 for(int i=0; i<n_faces; i++)
270 for(int j=0; j<face_extract[0]->seq_out->n_frames; j++)
271 {
272 real *tmp_ = face_extract[i]->seq_out->frames[j];
273 for(int k=0; k<output_size; k++)
274 if(norm)
275 {
276 real pix = tmp_[k]/255.0;
277 bin_file.write(&pix, sizeof(real), 1);
278 }
279 else bin_file.write(&tmp_[k], sizeof(real), 1);
280 }
281 }
282
283
284
285 delete allocator;
286 return(0);
287 }