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