bazar  1.3.1
image_classification_forest.cpp
Go to the documentation of this file.
1 /*
2 Copyright 2005, 2006 Computer Vision Lab,
3 Ecole Polytechnique Federale de Lausanne (EPFL), Switzerland.
4 All rights reserved.
5 
6 This file is part of BazAR.
7 
8 BazAR is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 2 of the License, or (at your option) any later
11 version.
12 
13 BazAR is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along with
18 BazAR; if not, write to the Free Software Foundation, Inc., 51 Franklin
19 Street, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21 #include <fstream>
22 #include <iomanip>
23 using namespace std;
24 
25 #include <starter.h>
27 
29  : image_classifier(_LearnProgress)
30 {
31  weights=0;
32 }
33 
34 image_classification_forest::image_classification_forest(int _image_width, int _image_height, int _class_number,
35  int _max_depth, int _tree_number,
36  LEARNPROGRESSION _LearnProgress)
37  : image_classifier(_image_width, _image_height, _class_number,_LearnProgress)
38 {
39  max_depth = _max_depth;
40  tree_number = _tree_number;
41 
43 
44  weights = new float[class_number];
45  for(int i = 0; i < class_number; i++)
46  weights[i] = 0;
47 }
48 
49 
50 bool image_classification_forest::load(string directory_name)
51 {
52  int i = 0;
53  bool ok;
54 
56  cout << "Reading Forest in " << directory_name << ":" << endl;
57 
58  // Read the trees:
59  do
60  {
61  char tree_filename[1000];
62  sprintf(tree_filename, "%s/tree%04d.txt", directory_name.data(), i);
63 
64  ifstream ifs(tree_filename);
65  ok = ifs.is_open();
66  if (ok)
67  {
68  cout << " Reading " << tree_filename << ": " << flush;
69 
71 
72  if ( !tree->load(tree_filename) )
73  {
74  delete tree;
75  return false;
76  }
77 
78  trees.push_back(tree);
79  i++;
80  }
81  } while(ok);
82  if (trees.size() == 0 ) return false;
83 
84  image_width = (*trees.begin())->image_width;
85  image_height = (*trees.begin())->image_height;
86  class_number = (*trees.begin())->class_number;
87  max_depth = (*trees.begin())->max_depth;
88 
89  // Read weight file:
90  weights = new float[class_number];
91  char weights_filename[1000];
92  sprintf(weights_filename, "%s/weights.txt", directory_name.data());
93  ifstream wfs(weights_filename);
94  for(i = 0; i < class_number; i++)
95  wfs >> weights[i];
96  for(vector<image_classification_tree *>::iterator tree_it = trees.begin(); tree_it < trees.end(); tree_it++)
97  (*tree_it)->root->load_probability_sums_recursive(wfs);
98  wfs.close();
99 
100  // Read threshold file:
101  if (thresholds != 0)
102  delete [] thresholds;
103  thresholds = new float [class_number];
104 
105  char thresholds_filename[1000];
106  sprintf(thresholds_filename, "%s/thresholds.txt", directory_name.data());
107  ifstream tfs(thresholds_filename);
108  for(i = 0; i < class_number; i++)
109  tfs >> thresholds[i];
110  tfs.close();
111 
112  // Read misclas rates file:
113  if (misclassification_rates != 0)
114  delete [] misclassification_rates;
116 
117  char misclassification_rates_filename[1000];
118  sprintf(misclassification_rates_filename, "%s/misclassification_rates.txt", directory_name.data());
119  ifstream rfs(misclassification_rates_filename);
120  if (rfs.good())
121  {
122  for(i = 0; i < class_number; i++)
123  rfs >> misclassification_rates[i];
124  rfs.close();
125  }
126  else
127  for(i = 0; i < class_number; i++)
128  misclassification_rates[i] = 0.42f;
129 
130  cout << "Done." << endl;
131 
132  return true;
133 }
134 
136 {
137  if (weights != 0) {
138  delete [] weights;
139  weights = 0;
140  }
141 
142  for(vector<image_classification_tree *>::iterator tree_it = trees.begin(); tree_it < trees.end(); tree_it++)
143  delete (*tree_it);
144 
145  if (thresholds != 0)
146  delete [] thresholds;
147 
148  if (misclassification_rates != 0)
149  delete [] misclassification_rates;
150 }
151 
153 {
154  directory_name = _directory_name;
155 }
156 
158 {
159  for(int i = 0; i < tree_number; i++)
160  {
161  if (LearnProgression!=0)
162  LearnProgression(BUILDING_TREE, i, tree_number);
163 
164  cout << "FOREST: BUILDING TREE # " << i << endl;
165 
168 
170  tree->root->index = 0;
171 
172  vector <image_classification_node*> L;
173  L.reserve(30);
174  L.push_back(tree->root);
175 
176  int new_node_index = 1;
177 
178  while(!L.empty())
179  {
180  cout << "BUILDING RANDOM TREE: ~ " << new_node_index << " nodes.\r" << flush;
181 
183  L.pop_back();
184 
186 
187  if (node->depth < max_depth - 2)
188  {
189  node->expand();
190 
191  for(int i = 0; i < node->children_number; i++)
192  L.push_back(node->children[i]);
193  }
194  else
195  node->end_recursion();
196 
197  for(int i = 0; i < node->children_number; i++)
198  {
199  node->children[i]->index = new_node_index;
200  new_node_index++;
201  }
202  }
203 
204  cout << "Random tree built (" << tree->node_number() << " nodes)." << endl;
205 
206  trees.push_back(tree);
207  }
208 }
209 
210 // Refine the posterior probabilities stored in the leaves for each tree
212 {
213  for(int i = 0; i < call_number; i++)
214  {
215  if (LearnProgression!=0)
216  LearnProgression(FOREST_REFINEMENT, i, call_number);
217 
218  cout << "FOREST REFINEMENT: " << call_number - i << "... " << (char)13 << flush;
219 
220  vector<image_class_example *> * examples = vg->generate_random_examples();
221 
222  for(vector<image_class_example *>::iterator example_it = examples->begin(); example_it < examples->end(); example_it++)
223  {
224  for(vector<image_classification_tree *>::iterator tree_it = trees.begin(); tree_it < trees.end(); tree_it++)
225  {
226  image_classification_node * node = (*tree_it)->root;
227  unsigned char * I = (unsigned char *)((*example_it)->preprocessed->imageData);
228 
229  while(!node->is_leaf())
230  {
231  int dot_product = (int)I[node->d1] - (int)I[node->d2];
232 
233  if (dot_product <= 0)
234  node = node->children[0];
235  else
236  node = node->children[1];
237  }
238  node->P[(*example_it)->class_index]++;
239  }
240  weights[(*example_it)->class_index]++;
241  }
242 
243  delete examples;
244 
245  vg->release_examples();
246  }
247 
248  cout << "Reweighted refinement: " << endl;
249 
250  for(int i = 0; i < class_number; i++)
251  if (weights[i] == 0)
252  weights[i] = 0;
253  else
254  weights[i] = 1 / weights[i];
255 
256  for(vector<image_classification_tree *>::iterator tree_it = trees.begin(); tree_it < trees.end(); tree_it++)
257  (*tree_it)->root->reestimate_probabilities_recursive(weights);
258 
259  cout << "Forest refinement done (" << call_number << " calls to generate_random_examples). " << endl;
260 }
261 
263 {
264  assert(weights);
265 
266  for(vector<image_classification_tree *>::iterator tree_it = trees.begin(); tree_it < trees.end(); tree_it++)
267  (*tree_it)->root->restore_occurances_recursive(weights);
268 
269  for(int i = 0; i < class_number; ++i)
270  weights[i] = weights[i] > 0 ? 1 / weights[i] : 0.0f;
271 }
272 
274 {
275  for(vector<image_classification_tree *>::iterator tree_it = trees.begin(); tree_it < trees.end(); tree_it++)
276  (*tree_it)->root->reset_class_occurances_recursive(class_index);
277 
278  weights[class_index] = 0.0f;
279 }
280 
282 {
283  int * inlier_total = new int[class_number];
284  int * total = new int[class_number];
285 
286  int ** correct_samples = new int*[class_number];
287  int ** uncorrect_samples = new int*[class_number];
288 
289  const float step = 0.01f;
290  int bin_number = int(1. / step);
291  for(int i = 0; i < class_number; i++)
292  {
293  inlier_total[i] = total[i] = 0;
294 
295  correct_samples[i] = new int[bin_number];
296  uncorrect_samples[i] = new int[bin_number];
297  for(int j = 0; j < bin_number; j++)
298  correct_samples[i][j] = uncorrect_samples[i][j] = 0;
299  }
300 
301  for(int i = 0; i < call_number; i++)
302  {
303  if (LearnProgression!=0)
304  LearnProgression(GENERATING_TESTING_SET, i, call_number);
305 
306  cout << "GENERATING TESTING SET: " << call_number - i << "... " << (char)13 << flush;
307 
308  vector<image_class_example *> * examples = vg->generate_random_examples();
309 
310  for(vector<image_class_example *>::iterator it = examples->begin(); it < examples->end(); it++)
311  {
312  float score;
313  int found_class_index = recognize(*it, &score);
314 
315  int bin_index = int(score / step);
316  if (bin_index < 0) bin_index = 0;
317  if (bin_index >= bin_number) bin_index = bin_number - 1;
318 
319  total[(*it)->class_index]++;
320  if ((*it)->class_index == found_class_index)
321  {
322  inlier_total[found_class_index]++;
323  correct_samples[found_class_index][bin_index]++;
324  }
325  else
326  uncorrect_samples[found_class_index][bin_index]++;
327  }
328 
329  delete examples;
330 
331  vg->release_examples();
332  }
333 
334  // Estimate inlier rates and estimate thresholds:
335  cout << "Testing: " << endl;
336  cout << "Classification rate = [#p | Y(p) = c = Y^(p)] / [#p | Y(p) = c = Y^(p) or Y(p) != c = Y^(p)]" << endl;
337  cout << "Ambiguity measure = [#p | Y(p) = c != Y^(p)] / [#p | Y(p) = c = Y^(p)]" << endl;
338 
339  if (misclassification_rates != 0)
340  delete [] misclassification_rates;
342 
343  int T = 0, IT = 0;
344  for(int i = 0; i < class_number; i++)
345  {
346  if (total[i] == 0)
347  misclassification_rates[i] = 0.5;
348  else
349  misclassification_rates[i] = 1.f - float(inlier_total[i]) / total[i];
350 
351  T += total[i];
352  IT += inlier_total[i];
353  }
354 
355  float inlier_percentage = 100.f * float(IT) / T;
356 
357  if (thresholds != 0)
358  delete [] thresholds;
359  thresholds = new float [class_number];
360 
361  float desired_inlier_rate = 0.6f;
362  float ambiguity_rate_mean = 0;
363  for(int i = 0; i < class_number; i++)
364  {
365  cout << "CLASS " << setw(4) << i << ": ";
366  int correct_number = 0, uncorrect_number = 0;
367  int j;
368  for(j = bin_number - 1; j >= 0; j--)
369  {
370  correct_number += correct_samples[i][j];
371  uncorrect_number += uncorrect_samples[i][j];
372  if (float(correct_number) / (correct_number + uncorrect_number) < desired_inlier_rate &&
373  (correct_number + uncorrect_number) > 10)
374  break;
375  }
376  thresholds[i] = j * step;
377  cout << setw(5) << total[i] << " generated samples, ";
378  cout << setw(4) << " T = " << setw(8) << thresholds[i] << ", ";
379  cout << setw(6) << setprecision(3) << 100. * float(inlier_total[i]) / total[i] << "% inliers, " << flush;
380 
381  correct_number = 0; uncorrect_number = 0;
382  for(int j = bin_number - 1; j >= 0; j--)
383  {
384  correct_number += correct_samples[i][j];
385  uncorrect_number += uncorrect_samples[i][j];
386  }
387  if (correct_number != 0)
388  {
389  ambiguity_rate_mean += float(uncorrect_number) / correct_number;
390  cout << "Ambig: " << setw(4) << setprecision(3) << float(uncorrect_number) / correct_number << endl;
391  }
392  else
393  {
394  ambiguity_rate_mean += 2.;
395  cout << "Ambig: +oo" << endl;
396  }
397  }
398  cout << "-------------------------------------------" << endl;
399  cout << " GLOBAL ESTIMATION: " << setprecision(4) << inlier_percentage << "% inliers." << endl;
400  ambiguity_rate_mean /= class_number;
401  cout << " E[Ambig] = " << ambiguity_rate_mean << endl;
402  cout << "-------------------------------------------" << endl;
403 
404  // Clear allocated arrays:
405  for(int i = 0; i < class_number; i++)
406  {
407  delete [] correct_samples[i];
408  delete [] uncorrect_samples[i];
409  }
410 
411  delete [] correct_samples;
412  delete [] uncorrect_samples;
413 
414  delete [] total;
415  delete [] inlier_total;
416 }
417 
418 int image_classification_forest::recognize(image_class_example * pv, float * confidence, int tree_number)
419 {
420  float * p = posterior_probabilities(pv, tree_number);
421  int best_class = 0;
422  float best_p = p[best_class];
423 
424  for(int i = 1; i < class_number; i++)
425  if (p[i] > best_p)
426  {
427  best_p = p[i];
428  best_class = i;
429  }
430 
431  delete [] p;
432 
433  if (confidence != 0)
434  *confidence = best_p;
435 
436  return best_class;
437 }
438 
440 {
441  float * p = new float[class_number];
442 
443  posterior_probabilities(pv, p, tree_number);
444 
445  return p;
446 }
447 
449 {
450  if (tree_number < 0)
451  {
452  for(int i = 0; i < class_number; i++)
453  p[i] = 0.;
454 
455  for(vector<image_classification_tree *>::iterator tree_it = trees.begin();
456  tree_it < trees.end();
457  tree_it++)
458  {
459  float * tree_p = (*tree_it)->posterior_probabilities(pv);
460 
461  for(int i = 0; i < class_number; i++)
462  p[i] += tree_p[i];
463  }
464 
465  float inv_tree_number = 1.f / trees.size();
466  for(int i = 0; i < class_number; i++)
467  p[i] *= inv_tree_number;
468  }
469  else
470  {
471  for(int i = 0; i < class_number; i++)
472  p[i] = 0.;
473 
474  int n = 0;
475  if (tree_number < 0)
476  tree_number = trees.size();
477 
478  for(vector<image_classification_tree *>::iterator tree_it = trees.begin();
479  tree_it < trees.end();
480  tree_it++)
481  {
482  float * tree_p = (*tree_it)->posterior_probabilities(pv);
483 
484  for(int i = 0; i < class_number; i++)
485  p[i] += tree_p[i];
486 
487  n++;
488  if (n > tree_number) break;
489  }
490 
491  float inv_class_number = 1.f / tree_number;
492  for(int i = 0; i < class_number; i++)
493  p[i] *= inv_class_number;
494  }
495 }
496 
498 {
499  class_number = new_class_number;
500 
501  if(weights != 0) {
502  delete [] weights;
503  weights = 0;
504  }
505  weights = new float[class_number];
506  for(int i = 0; i < class_number; i++)
507  weights[i] = 0;
508 
509  for(vector<image_classification_tree *>::iterator tree_it = trees.begin();
510  tree_it < trees.end();
511  tree_it++)
512  {
513  (*tree_it)->change_class_number_and_reset_probabilities(new_class_number);
514  }
515 }
516 
517 bool image_classification_forest::save(string directory_name)
518 {
519  int tree_index = 0;
520 
521  for(vector<image_classification_tree *>::iterator tree_it = trees.begin();
522  tree_it < trees.end();
523  tree_it++)
524  {
525  char tree_name[1000];
526 
527  sprintf(tree_name, "%s/tree%04d.txt", directory_name.data(), tree_index);
528 
529  (*tree_it)->save(tree_name);
530 
531  tree_index++;
532  }
533 
534  // Save thresholds:
535  char thresholds_filename[1000];
536  sprintf(thresholds_filename, "%s/thresholds.txt", directory_name.data());
537  ofstream tfs(thresholds_filename);
538  if (!tfs.good()) return false;
539  tfs << setw(12) << setprecision(12);
540  for(int i = 0; i < class_number; i++)
541  tfs << thresholds[i] << endl;
542  tfs.close();
543 
544  // Save misclassification rates:
545  char misclassification_rates_filename[1000];
546  sprintf(misclassification_rates_filename, "%s/misclassification_rates.txt", directory_name.data());
547  ofstream rfs(misclassification_rates_filename);
548  for(int i = 0; i < class_number; i++)
549  rfs << misclassification_rates[i] << endl;
550  rfs.close();
551 
552  // Save weights and probability_sum's.
553  char weights_filename[1000];
554  sprintf(weights_filename, "%s/weights.txt", directory_name.data());
555  ofstream wfs(weights_filename);
556  for(int i = 0; i < class_number; i++)
557  wfs << weights[i] << endl;
558  for(vector<image_classification_tree *>::iterator tree_it = trees.begin(); tree_it < trees.end(); tree_it++)
559  {
560  (*tree_it)->root->save_probability_sums_recursive(wfs);
561  wfs << endl;
562  }
563  wfs.close();
564 
565 
566  return true;
567 }
568