selfQuotientImage.cc

  1 const char *help = "\
  2 progname: selfQotientImage.cc\n\
  3 code2html: This program reads a pgm image (grayscale) and normalizes the lighting conditions according to the Self-Quotient Image approach.\n\
  4 \n\
  5 The input image is filtered (weighed gaussian) several times, and the illumination-free\n\
  6 representation is obtained by dividing the input image by the filtered ones,\n\
  7 as described in the article by Wang, Li and Wang: \n\
  8 'Face Recognition under Varying Lighting conditions using Self Quotient Image'.\n\
  9 \n\
 10 version: Torch3 vision2.0, 2004-2005\n\
 11 (c) Guillaume Heusch (heusch@idiap.ch)\n";
 12 
 13 
 14 #include "ImageGray.h"
 15 #include "DiskXFile.h"
 16 #include "CmdLine.h"
 17 #include "ipWeighedGaussian.h"
 18 #include "ipHistoEqual.h"
 19 #include "Timer.h"
 20 
 21 
 22 using namespace Torch;
 23 
 24 int main(int argc, char **argv)
 25 {
 26     Timer timer;
 27     
 28 	char *image_filename;
 29 	char *sqi_filename;
 30 	int nb_filters = 3;
 31 	int min_size;
 32 	int middle_size;
 33 	int max_size;
 34 	bool verbose;
 35 	bool histo;
 36 
 37 	
 38 	// ------------------------ COMMAND LINE ---------------------------------------------------------------------
 39   	CmdLine cmd;
 40 	cmd.setBOption("write log", false);
 41   	cmd.info(help);
 42 
 43   	cmd.addText("\nArguments:");
 44   	cmd.addSCmdArg("image_filename", &image_filename, "input image filename");
 45 	cmd.addSCmdArg("sqi_filename", &sqi_filename, "self quotient image filename");
 46 	
 47   	cmd.addText("\nOptions:");
 48   	cmd.addBCmdOption("-verbose", &verbose, false, "verbose");
 49 	cmd.addICmdOption("-min_size", &min_size, 3, "size of the smallest convolution kernel (must be odd)");
 50 	cmd.addICmdOption("-middle_size", &middle_size, 9, "size of the 'middle' convolution kernel (must be odd)");
 51 	cmd.addICmdOption("-max_size", &max_size, 15, "size of the biggest convolution kernel (must be odd)");
 52 	cmd.addBCmdOption("-histo", &histo, false, "apply histogram equalization on the result");
 53 	
 54 	cmd.read(argc, argv);
 55 
 56 	Allocator *allocator = new Allocator;
 57 	// ----------------------- LOAD IMAGE --------------------------------------------------------------------------
 58   	DiskXFile *image_file = NULL;
 59 	Image *image_in = NULL;
 60 
 61 	image_in = new(allocator) ImageGray();
 62 	image_in->setBOption("verbose", verbose);
 63 	
 64 	image_file = new(allocator) DiskXFile(image_filename, "r");
 65 	image_in->loadXFile(image_file);
 66 
 67 	if(verbose)
 68 	{
 69 		print("Image info:\n");
 70 		print("   width = %d\n", image_in->width);
 71 		print("   height = %d\n", image_in->height);
 72 		print("   format = %s (%d)\n", image_in->coding, image_in->n_planes);
 73 	}
 74 
 75 	
 76 	// ---------------- MULTI-SCALE ANISOTROPIC GAUSSIAN FILTERING ------------------------------------------------------
 77 
 78 	Image *filtered_array [nb_filters];
 79 	ipCore *weighedGaussian = NULL;
 80 
 81 	for (int filter_index = 0; filter_index < nb_filters; filter_index++)
 82 	  filtered_array[filter_index] = NULL;
 83 	
 84 
 85 	for (int filter_index = 0; filter_index < nb_filters; filter_index++) {
 86 	  
 87 	  int size = 0;
 88 
 89 	  if (filter_index == 0)
 90 	    size = min_size;
 91 	  if (filter_index == 1)
 92 	    size = middle_size;
 93 	  if (filter_index == 2)
 94 	    size = max_size;
 95 	 
 96 	  weighedGaussian = new(allocator) ipWeighedGaussian(size, image_in->width, image_in->height, "gray");
 97 	  weighedGaussian->process(image_in);
 98 	  
 99 	  filtered_array[filter_index] = new(allocator) ImageGray();
100 	  filtered_array[filter_index]->copyFrom(image_in->width,image_in->height, weighedGaussian->seq_out->frames[0], "gray", 255);
101 	  filtered_array[filter_index]->updatePixmapFromData();
102 	    
103 	  // ************************************************
104 	  // IF YOU WANT TO SAVE THE FILTERED IMAGES 
105 	  // -----------------------------------------------
106 	  // char filename[50];
107 	  // sprintf(filename, "filtered_%ix%i", size, size);
108 	  // strcat(filename, ".pgm");
109 	  // rescale(filtered_array[filter_index]->data, filtered_array[filter_index]->width, filtered_array[filter_index]->height);
110 	  // filtered_array[filter_index]->updatePixmapFromData();
111 	  // filtered_array[filter_index]->save(filename); 
112 	  // ***********************************************
113 	}
114 
115 
116 	// ---------------------- BUILD AND SAVE THE SELF-QUOTIENT IMAGE --------------------------------------------
117 
118 	Image *qi_array [nb_filters];
119 	for (int i = 0; i < nb_filters; i++)
120 	  qi_array[i] = NULL;
121 
122 	
123 	// build the normalized images
124 	for (int filter_index = 0; filter_index < nb_filters; filter_index++) {
125 	  
126 	  qi_array[filter_index] = new(allocator) ImageGray(image_in->width, image_in->height);
127 
128 	  for (int i=0; i<(image_in->width*image_in->height); i++) {
129 	    qi_array[filter_index]->data[i] = log((image_in->data[i]+1)/(filtered_array[filter_index]->data[i]+1));
130 	  }
131 
132 	  int size = 0;
133 
134 	  if (filter_index == 0)
135 	    size = min_size;
136 	  if (filter_index == 1)
137 	    size = middle_size;
138 	  if (filter_index == 2)
139 	    size = max_size;
140 	}
141 	    
142 
143 	Image *sqi = NULL;
144 	sqi = new(allocator) ImageGray(image_in->width, image_in->height);
145 	sqi->setBOption("verbose", verbose);
146 
147 	// ---------------------- TEMP --------------
148 	for (int n_image = 0; n_image < nb_filters; n_image++) {
149 	  for (int i=0; i<(sqi->width*sqi->height); i++)
150 	    sqi->data[i] += qi_array[n_image]->data[i];
151 	}
152 	
153 
154 	//rescale between 0-255
155 	scaleGray(sqi->width, sqi->height, sqi->data); 
156        
157 	
158 	// histogram equalization if specified
159 	ipCore *histoEq = NULL;
160 
161 	if (histo) {   
162 	  histoEq = new(allocator) ipHistoEqual(image_in->width, image_in->height, "gray");
163 	  histoEq->process(sqi);
164 	}
165 
166 	Image *image_out = NULL;
167 	image_out = new(allocator) ImageGray();
168 	image_out->setBOption("verbose", verbose);
169  
170 	if (histo)
171 	  image_out->copyFrom(image_in->width, image_in->height, histoEq->seq_out->frames[0], "gray", 255);
172 	else
173 	  image_out->copyFrom(image_in->width, image_in->height, sqi->data, "gray", 255);
174 	
175 	image_out->updatePixmapFromData();
176 	image_out->save(sqi_filename);
177 
178 
179 	// ----------------------- CLEAN UP -----------------------------------------------------------------------
180 	delete allocator;
181 	
182 	print("time elapsed: %g\n", timer.getTime());
183 	timer.stop();
184 	
185 	return(0);
186 }