haarscan.cc

  1 const char *help = "\
  2 progname: haarscan.cc\n\
  3 code2html: This program detects objects (such as faces) in an image using a cascade of haar-like classifiers.\n\
  4 version: Torch3 vision2.0, 2004-2005\n\
  5 (c) Yann Rodriguez (rodrig@idiap.ch) and Sebastien Marcel (marcel@idiap.ch)\n";
  6 
  7 // image
  8 #include "ImageGray.h"
  9 #include "ImageRgb.h"
 10 #include "Rectangle2D.h"
 11 
 12 // image loader
 13 #include "xtprobeImageDiskXFile.h"
 14 #include "jpegDiskXFile.h"
 15 
 16 // pattern detector
 17 #include "HaarPatternDetect.h"
 18 
 19 // edge
 20 #include "ipSobel.h"
 21 
 22 // misc
 23 #include "DiskXFile.h"
 24 #include "CmdLine.h"
 25 #include "MTimer.h"
 26 
 27 using namespace Torch;
 28 
 29 int main(int argc, char **argv)
 30 {
 31 	char *image_filename;
 32 	bool verbose;
 33 	      
 34         int patternWmin;
 35         int patternHmin;
 36         int minWsize;
 37         int maxWsize;
 38         real scale_factor;
 39         real stepx_factor;
 40         real stepy_factor;
 41 
 42         real MeanMin;
 43         real MeanMax;
 44         real StdvMin;
 45         real StdvMax;
 46 	bool pruning;
 47 	real threshold_edges_min;
 48 	real threshold_edges_max;
 49 
 50 	char *model_filename;
 51 	real model_threshold;
 52 	bool realstump;
 53  
 54  
 55 	real surfoverlap_fusion;
 56 	real threshold_activation;
 57 
 58 	char *dirname;
 59 
 60 	int nbest;
 61 	bool savepos;
 62 	bool draw;
 63 	bool savejpg;
 64 
 65   	
 66 	// Construct the command line.
 67         // ---------------------------
 68 	CmdLine cmd;
 69 	cmd.setBOption("write log", false);
 70   	cmd.addText("\nArguments:");
 71   	cmd.addSCmdArg("image filename", &image_filename, "image filename");
 72   	cmd.addText("\nOptions:");
 73   	cmd.addBCmdOption("-verbose", &verbose, false, "verbose");
 74         cmd.addText("\nScanning Options:");
 75         cmd.addICmdOption("-patternWmin", &patternWmin, 19, "pattern width min");
 76         cmd.addICmdOption("-patternHmin", &patternHmin, 19, "pattern height min");
 77         cmd.addICmdOption("-minWsize", &minWsize, -1, "width min");
 78         cmd.addICmdOption("-maxWsize", &maxWsize, -1, "width max");
 79         cmd.addRCmdOption("-scalefactor", &scale_factor, 0.125, "scale factor");
 80         cmd.addRCmdOption("-stepxfactor", &stepx_factor, 0.0625, "step x factor");
 81         cmd.addRCmdOption("-stepyfactor", &stepy_factor, 0.0625, "step y factor");
 82 	cmd.addText("\nPruning Options:");
 83 	cmd.addBCmdOption("-pruning", &pruning, false, "use pruning");
 84 	cmd.addRCmdOption("-mmin", &MeanMin, 0.041, "mean min");
 85 	cmd.addRCmdOption("-mmax", &MeanMax, 0.890, "mean max");
 86 	cmd.addRCmdOption("-vmin", &StdvMin, 0.0204354, "variance min");
 87 	cmd.addRCmdOption("-vmax", &StdvMax, 0.382121, "variance max");
 88 	cmd.addRCmdOption("-emin", &threshold_edges_min, 0.1, "edge threshold min");
 89 	cmd.addRCmdOption("-emax", &threshold_edges_max, 0.5, "edge threshold max");
 90 	cmd.addText("\nModel Options:");
 91 	cmd.addSCmdOption("-model", &model_filename, "./models/haar5-stump-cascade19x19-12-2-150", "haar cascade model filename");
 92 	cmd.addRCmdOption("-threshold", &model_threshold, -0.0705, "Model threshold");
 93         cmd.addBCmdOption("-realstump", &realstump, false, "real stump classifiers");
 94 	cmd.addText("\nFusion Options:");
 95 	cmd.addRCmdOption("-surfoverlapfusion", &surfoverlap_fusion, 0.2, "threshold for fusion of overlapped patterns");
 96 	cmd.addRCmdOption("-threshold_activation", &threshold_activation, 1.5, "threshold after fusion");
 97 	cmd.addText("\nMiscellaneous Options:");
 98 	cmd.addSCmdOption("-dir", &dirname, ".", "directory to store ouput files");
 99         cmd.addBCmdOption("-savepos", &savepos, false, "save pos file");
100         cmd.addBCmdOption("-draw", &draw, false, "draw ppm image with detections");
101         cmd.addBCmdOption("-savejpg", &savejpg, false, "save in jpeg instead of jpeg");
102         cmd.addICmdOption("-nbest", &nbest, -1, "nbest detections (all if -1)");
103 	cmd.read(argc, argv);
104 
105 
106 	Allocator *allocator = new Allocator;
107 	
108 	
109 	// extract basename from filename.
110 	// --------------------------------
111 	char basename[256];
112 	char *extension;
113 	char *separator;
114 	strcpy(basename, image_filename);
115         extension = (char *) strrchr(basename, '.');
116         if(extension != NULL) *extension = '\0';
117 	separator = (char *) rindex(basename, '/');
118 	if(separator != NULL)
119 	{
120 		separator++;
121 		strcpy(basename, separator);
122 	}
123 
124 	
125 	// load image to scan.
126         // --------------------
127 	Image *image;
128 	ImageDiskXFile *image_file;
129 	image_file = new(allocator) xtprobeImageDiskXFile(image_filename, "r");
130 	image = new(allocator) ImageGray();
131 	image->setBOption("verbose", verbose);
132 	image->loadImageXFile(image_file);
133 	allocator->free(image_file);
134 
135         int width = image->width;
136         int height = image->height;
137 
138 	Sequence *realimage = new(allocator) Sequence(1, width * height);
139 	for(int i = 0 ; i < width * height ; i++) 
140 		realimage->frames[0][i] = image->data[i] / 255.0;
141 
142 	
143 	// pruning.
144 	// ---------
145 	real *pruning_ii = NULL;
146 
147 	if(pruning)
148 	{
149 		ipCore *edges = new(allocator) ipSobel(width, height, "float");
150 		edges->setROption("threshold", 0.4);
151 		Sequence *realedges = new(allocator) Sequence(&edges->seq_out->frames[3], 1, width * height);	
152 		ipCore *integralimagemachine_edges = new(allocator) ipIntegralImage(width, height, "gray");
153 		edges->init();
154 		edges->process(realimage);
155 		integralimagemachine_edges->init();
156 		integralimagemachine_edges->process(realedges);
157 
158 		pruning_ii = integralimagemachine_edges->seq_out->frames[0];
159 	}
160 	
161 	// Detection.
162 	// -----------
163 	PatternDetect *patterndetect;
164 	
165 	patterndetect = new(allocator) HaarPatternDetect(
166 			model_filename, 
167 	      		model_threshold,
168 	      		width, height, 
169 			patternWmin, patternHmin, 
170 			minWsize, maxWsize, 
171 			stepx_factor, stepy_factor, scale_factor,
172 			MeanMin, MeanMax, StdvMin, StdvMax,
173 			surfoverlap_fusion, threshold_activation, 
174 			pruning_ii, 
175 			threshold_edges_min, threshold_edges_max,
176 			1000, verbose, realstump);
177 				
178 
179 	// Processing.
180         // ---------------
181 	MTimer *timer = new(allocator) MTimer();
182 	timer->reset();
183 	patterndetect->init();
184 	patterndetect->process(realimage);
185 	patterndetect->stat();
186 	timer->stop();
187 	print("processing time: %d' %d'' %dms\n\n", timer->minutes, timer->seconds, timer->mseconds);
188 	
189 	//	
190 	DiskXFile *posoutput = NULL;
191 	char str[250];
192 
193 	if(patterndetect->n_patterns > 0)
194 	{
195 	   	ImageRgb *outputimage = NULL;
196 
197 		if(draw)
198 		{
199 	   		outputimage = new(allocator) ImageRgb(width, height);
200 			outputimage->copyFrom(image);
201 		}
202 		
203 		if(savepos)
204 		{
205 			sprintf(str, "%s/%s.pos", dirname, basename);
206 			posoutput = new(allocator) DiskXFile(str, "w");
207 		}
208 
209 		Color facecolor = green;
210 		Rectangle2D rect;
211 		
212 		int P = patterndetect->n_patterns;
213 		
214 		if(nbest != -1)
215 		{
216 			if(nbest < P) P = nbest;
217 			print("saving %d-bests\n", P);
218 		}
219 		
220 		if(savepos) posoutput->printf("%d\n", P);
221 		
222 		for(int i = 0 ; i < P ; i++)
223 		{
224 			if(verbose)
225 				print("DETECTION [%02d] %d %d %d %d %g %d %g %g\n", 
226                                         i,
227                                         patterndetect->patterns[i]->x, 
228                                         patterndetect->patterns[i]->y, 
229                                         patterndetect->patterns[i]->w, 
230                                         patterndetect->patterns[i]->h, 
231                                         patterndetect->patterns[i]->scale, 
232                                         patterndetect->patterns[i]->view, 
233                                         patterndetect->patterns[i]->confidence,
234                                         patterndetect->patterns[i]->activation);
235 
236 			rect.reset(	patterndetect->patterns[i]->x, patterndetect->patterns[i]->y, 
237 			      		patterndetect->patterns[i]->w, patterndetect->patterns[i]->h);
238 
239 			if(draw) rect.draw(outputimage, facecolor);
240 
241 			if(savepos)
242 				posoutput->printf("%d %d %d %d\n",
243 				      patterndetect->patterns[i]->x,
244 				      patterndetect->patterns[i]->y,
245 				      patterndetect->patterns[i]->w,
246 				      patterndetect->patterns[i]->h);
247 		}
248 		if(verbose) print("\n");
249 	   
250 		if(draw)
251 		{
252 		   	if(savejpg)
253 			{
254 			   	sprintf(str, "%s/%s-detect.jpg", dirname, basename);
255 				jpegDiskXFile *jpeg_file = new(allocator) jpegDiskXFile(str, "w");
256 				jpeg_file->writeHeader(outputimage->width, outputimage->height);
257 				jpeg_file->writePixmap(outputimage->pixmap);
258 				allocator->free(jpeg_file);
259 			}
260 			else
261 			{
262 				sprintf(str, "%s/%s-detect.ppm", dirname, basename);
263 
264 				outputimage->save(str);
265 			}
266 			allocator->free(outputimage);
267 		}
268 	}
269 
270 	delete allocator;
271 
272 	return(0);
273 }