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 }