bazar  1.3.1
affine_image_generator.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 <stdlib.h>
22 #include <math.h>
23 #include <iostream>
24 
25 #include <starter.h>
26 #include "affine_image_generator.h"
27 
28 using namespace std;
29 
30 // Used for randomizing precomputed white noise
31 static const int prime = 307189;
32 
34 {
35  original_image = 0;
36  processed_original_image = 0;
37  affine_image = 0;
38  smoothed_generated_object_view = 0;
39  orientation_corrector = 0;
40 
41  white_noise = new char[prime];
42  limited_white_noise = new char[prime];
43 
44  set_default_values();
45 
46  local_keypoint_array = new object_keypoint[affine_image_generator::max_point_number];
47 }
48 
50 {
51  if (original_image != 0)
52  cvReleaseImage(&original_image);
53  if (processed_original_image != 0)
54  cvReleaseImage(&processed_original_image);
55  if (affine_image != 0)
56  cvReleaseImage(&affine_image);
57  if (smoothed_generated_object_view != 0)
58  delete smoothed_generated_object_view;
59  if (orientation_corrector != 0)
60  delete orientation_corrector;
61  delete[] local_keypoint_array;
62 
63  if (white_noise) delete[] white_noise;
64  if (limited_white_noise) delete[] limited_white_noise;
65 }
66 
68 {
69  localization_noise = 0;
70 
71  set_noise_level(20);
72 
73  set_range_variation_for_theta(0, float(2.*3.1416));
74  set_range_variation_for_phi(0, 3.1516f);
75  independent_scaling(0.5, 1.5, 0.5, 1.5);
76  // constrained_scaling(0.7, 1.7, 0.9, 1.1);
77 
78  set_use_orientation_correction(true);
79 
80  set_use_random_background(false);
81 
82  set_patch_size(32);
83  set_level_number(3);
84  set_gaussian_smoothing_kernel_size(3);
85 
86  set_add_gaussian_smoothing(false);
87  set_change_intensities(false);
88 }
89 
91 {
92  this->noise_level = noise_level;
93 
94  index_white_noise = 0;
95  for(int i = 0; i < prime; i++)
96  {
97  limited_white_noise[i] = char(rand() % (2 * noise_level) - noise_level);
98  white_noise[i] = char(rand() % 256);
99  }
100 }
101 
102 void affine_image_generator::set_original_image(IplImage * p_original_image,
103  int _u_corner1, int _v_corner1, int _u_corner2, int _v_corner2,
104  int _u_corner3, int _v_corner3, int _u_corner4, int _v_corner4,
105  int affine_image_width, int affine_image_height)
106 {
107  if (original_image != 0)
108  cvReleaseImage(&original_image);
109  original_image = cvCloneImage(p_original_image);
110 
111  if (processed_original_image != 0)
112  cvReleaseImage(&processed_original_image);
113  processed_original_image = cvCloneImage(p_original_image);
114 
115  if (affine_image != 0)
116  cvReleaseImage(&affine_image);
117  if (affine_image_width < 0)
118  affine_image = cvCloneImage(p_original_image);
119  else
120  affine_image = cvCreateImage(cvSize(affine_image_width, affine_image_height), IPL_DEPTH_8U, 1);
121 
122  if (smoothed_generated_object_view != 0)
123  delete smoothed_generated_object_view;
124  smoothed_generated_object_view = new object_view(original_image->width, original_image->height, level_number);
125 
126  if (orientation_corrector != 0)
127  delete orientation_corrector;
128  orientation_corrector = new keypoint_orientation_corrector(original_image->width, original_image->height,
129  patch_size, level_number);
130 
131  set_roi(_u_corner1, _v_corner1,
132  _u_corner2, _v_corner2,
133  _u_corner3, _v_corner3,
134  _u_corner4, _v_corner4);
135 }
136 
138 {
139 
140  if (original_image != 0)
141  cvReleaseImage(&original_image);
142  original_image = cvCloneImage(preprocessed);
143 
144  if (processed_original_image != 0)
145  cvReleaseImage(&processed_original_image);
146  processed_original_image = cvCloneImage(preprocessed);
147 
148  if (affine_image != 0)
149  cvReleaseImage(&affine_image);
150  affine_image = cvCloneImage(preprocessed);
151 
152  if (smoothed_generated_object_view != 0)
153  delete smoothed_generated_object_view;
154  smoothed_generated_object_view = new object_view(preprocessed->width, preprocessed->height, level_number);
155 
156  if (orientation_corrector != 0)
157  delete orientation_corrector;
158  orientation_corrector = new keypoint_orientation_corrector(preprocessed->width, preprocessed->height,
159  patch_size, level_number);
160 
161  u_corner1 = 0; v_corner1 = 0;
162  u_corner2 = preprocessed->width - 1; v_corner2 = 0;
163  u_corner3 = preprocessed->width - 1; v_corner3 = preprocessed->height - 1;
164  u_corner4 = 0; v_corner4 = preprocessed->height - 1;
165 }
166 
167 void affine_image_generator::set_object_keypoints(object_keypoint * keypoint_array, int p_point_number)
168 {
169  used_keypoint_array = keypoint_array;
170  point_number = p_point_number;
171 }
172 
174 {
175  used_keypoint_array = local_keypoint_array;
176  point_number = 0;
177 }
178 
179 void affine_image_generator::add_keypoint(float u, float v, int scale, int class_index)
180 {
181  assert((unsigned)point_number < 1000);
182 
183  local_keypoint_array[point_number].M[0] = u;
184  local_keypoint_array[point_number].M[1] = v;
185  local_keypoint_array[point_number].scale = float(scale);
186  local_keypoint_array[point_number].class_index = class_index;
187  point_number++;
188 }
189 
191 {
192  level_number = p_level_number;
193 
194  if (affine_image != 0)
195  {
196  if (orientation_corrector != 0)
197  delete orientation_corrector;
198  orientation_corrector = new keypoint_orientation_corrector(affine_image->width, affine_image->height,
199  patch_size, level_number);
200 
201  if (smoothed_generated_object_view != 0)
202  delete smoothed_generated_object_view;
203  smoothed_generated_object_view = new object_view(affine_image->width, affine_image->height, level_number);
204  }
205 }
206 
208 {
209  patch_size = p_patch_size;
210 
211  if (original_image != 0)
212  {
213  if (orientation_corrector != 0)
214  delete orientation_corrector;
215 
216  orientation_corrector = new keypoint_orientation_corrector(affine_image->width, affine_image->height,
217  patch_size, level_number);
218  }
219 }
220 
221 void affine_image_generator::set_roi(int _u_corner1, int _v_corner1,
222  int _u_corner2, int _v_corner2,
223  int _u_corner3, int _v_corner3,
224  int _u_corner4, int _v_corner4)
225 {
226  if (_u_corner1 >= 0)
227  {
228  u_corner1 = _u_corner1; v_corner1 = _v_corner1;
229  u_corner2 = _u_corner2; v_corner2 = _v_corner2;
230  u_corner3 = _u_corner3; v_corner3 = _v_corner3;
231  u_corner4 = _u_corner4; v_corner4 = _v_corner4;
232  }
233  else
234  {
235  u_corner1 = 0; v_corner1 = 0;
236  u_corner2 = original_image->width - 1; v_corner2 = 0;
237  u_corner3 = original_image->width - 1; v_corner3 = original_image->height - 1;
238  u_corner4 = 0; v_corner4 = original_image->height - 1;
239  }
240 
241  cvSmooth(original_image, processed_original_image, CV_MEDIAN, 3, 3);
242  for(int j = 0; j < processed_original_image->height; j++)
243  {
244  unsigned char * row = mcvRow(processed_original_image, j, unsigned char);
245  for(int i = 0; i < processed_original_image->width; i++)
246  if (i <= u_corner1 || i <= u_corner4 || i >= u_corner2 || i >= u_corner3 ||
247  j <= v_corner1 || j <= v_corner2 || j >= v_corner3 || j >= v_corner4)
248  row[i] = 128;
249  else
250  if (row[i] == 128) row[i] = 127;
251  }
252 }
253 
254 static int min4(int a, int b, int c, int d)
255 {
256  return MIN(a, MIN(b, MIN(c,d)));
257 }
258 
259 static int max4(int a, int b, int c, int d)
260 {
261  return MAX(a, MAX(b, MAX(c,d)));
262 }
263 
264 static float min4(float a, float b, float c, float d)
265 {
266  return MIN(a, MIN(b, MIN(c,d)));
267 }
268 
269 static float max4(float a, float b, float c, float d)
270 {
271  return MAX(a, MAX(b, MAX(c,d)));
272 }
273 
275 {
276  int border_size = 2;
277 
278  if (u - border_size < min4(u_corner1, u_corner2, u_corner3, u_corner4)) return false;
279  if (v - border_size < min4(v_corner1, v_corner2, v_corner3, v_corner4)) return false;
280  if (u + border_size > max4(u_corner1, u_corner2, u_corner3, u_corner4)) return false;
281  if (v + border_size > max4(v_corner1, v_corner2, v_corner3, v_corner4)) return false;
282 
283  return true;
284 }
285 
286 
288 void affine_image_generator::set_range_variation_for_theta(float p_min_theta, float p_max_theta)
289 {
290  min_theta = p_min_theta;
291  max_theta = p_max_theta;
292 }
293 
295 void affine_image_generator::set_range_variation_for_phi(float p_min_phi, float p_max_phi)
296 {
297  min_phi = p_min_phi;
298  max_phi = p_max_phi;
299 }
300 
302 void affine_image_generator::independent_scaling(float p_min_lambda1, float p_max_lambda1,
303  float p_min_lambda2, float p_max_lambda2)
304 {
305  scaling_method = 0;
306 
307  min_lambda1 = p_min_lambda1;
308  max_lambda1 = p_max_lambda1;
309 
310  min_lambda2 = p_min_lambda2;
311  max_lambda2 = p_max_lambda2;
312 }
313 
315 void affine_image_generator::constrained_scaling(float p_min_lambda1, float p_max_lambda1,
316  float p_min_lambda2, float p_max_lambda2,
317  float p_min_l1_l2, float p_max_l1_l2)
318 {
319  scaling_method = 1;
320 
321  min_lambda1 = p_min_lambda1;
322  max_lambda1 = p_max_lambda1;
323 
324  min_lambda2 = p_min_lambda2;
325  max_lambda2 = p_max_lambda2;
326 
327  min_l1_l2 = p_min_l1_l2;
328  max_l1_l2 = p_max_l1_l2;
329 }
330 
331 
333 {
334  float theta = min_theta + rand_01() * (max_theta - min_theta);
335  float phi = min_phi + rand_01() * (max_phi - min_phi);
336  float lambda1, lambda2;
337  int image_width = affine_image->width;
338  int image_height = affine_image->height;
339 
340  if (scaling_method == 0)
341  {
342  lambda1 = min_lambda1 + rand_01() * (max_lambda1 - min_lambda1);
343  lambda2 = min_lambda2 + rand_01() * (max_lambda2 - min_lambda2);
344  }
345  else
346  {
347  do
348  {
349  lambda1 = min_lambda1 + rand_01() * (max_lambda1 - min_lambda1);
350  lambda2 = min_lambda2 + rand_01() * (max_lambda2 - min_lambda2);
351  } while (lambda1 * lambda2 < min_l1_l2 || lambda1 * lambda2 > max_l1_l2);
352  }
353 
355  image_width / 2, image_height / 2,
356  theta, phi,
357  lambda1, lambda2,
358  0, 0);
359  int Tx, Ty;
360  float nu0, nv0, nu1, nv1, nu2, nv2, nu3, nv3;
361 
362  affine_transformation(a, image_width, image_height, float(u_corner1), float(v_corner1), nu0, nv0);
363  affine_transformation(a, image_width, image_height, float(u_corner2), float(v_corner2), nu1, nv1);
364  affine_transformation(a, image_width, image_height, float(u_corner3), float(v_corner3), nu2, nv2);
365  affine_transformation(a, image_width, image_height, float(u_corner4), float(v_corner4), nu3, nv3);
366 
367  // Moves two of the four corners on the borders of the image to maximize the visible part of the generated view:
368  if (rand() % 2 == 0)
369  Tx = - int(min4(nu0, nu1, nu2, nu3)) + patch_size;
370  else
371  Tx = image_width - int(max4(nu0, nu1, nu2, nu3)) - patch_size;
372 
373  if (rand() % 2 == 0)
374  Ty = -int(min4(nv0, nv1, nv2, nv3)) + patch_size;
375  else
376  Ty = image_height - int(max4(nv0, nv1, nv2, nv3)) - patch_size;
377 
379  image_width / 2, image_height / 2,
380  theta, phi,
381  lambda1, lambda2,
382  float(Tx), float(Ty));
383 }
384 
386 {
387  int image_width = affine_image->width;
388  int image_height = affine_image->height;
389 
391  image_width / 2, image_height / 2,
392  0, 0,
393  1., 1.,
394  0, 0);
395 }
396 
397 void affine_image_generator::affine_transformation(float p_a[6], int width, int height,
398  float u, float v,
399  float & nu, float & nv)
400 {
401  float det = p_a[0] * p_a[4] - p_a[3] * p_a[1];
402 
403  nu = width / 2 + 1.f / det * ( p_a[4] * (u - p_a[2]) - p_a[1] * (v - p_a[5]));
404  nv = height / 2 + 1.f / det * (-p_a[3] * (u - p_a[2]) + p_a[0] * (v - p_a[5]));
405 }
406 
407 void affine_image_generator::inverse_affine_transformation(float p_a[6], int width, int height,
408  float u, float v,
409  float & nu, float & nv)
410 {
411  nu = p_a[0] * (u - width / 2) + p_a[1] * (v - height / 2) + p_a[2];
412  nv = p_a[3] * (u - width / 2) + p_a[4] * (v - height / 2) + p_a[5];
413 }
414 
415 void affine_image_generator::affine_transformation(float u, float v, float & nu, float & nv)
416 {
417  affine_transformation(a, affine_image->width, affine_image->height, u, v, nu, nv);
418 }
419 
420 void affine_image_generator::inverse_affine_transformation(float u, float v, float & nu, float & nv)
421 {
422  inverse_affine_transformation(a, affine_image->width, affine_image->height, u, v, nu, nv);
423 }
424 
426 {
427  if (use_orientation_correction)
428  {
429  // Lowe orientation:
430  int s = (int)pv->point2d->scale;
431 
433  orientation_corrector->estimate_orientation_in_radians(ov->image[s],
434  int(pv->point2d->u), int(pv->point2d->v),
435  ov->gradX[s], ov->gradY[s]);
436 
437  assert(pv->preprocessed);
438 
439  orientation_corrector->correct_orientationf(ov->image[s],
440  pv->point2d->u, pv->point2d->v,
441  pv->preprocessed,
443  }
444  else
445  {
446  int s = (int)pv->point2d->scale;
447  assert(pv->preprocessed);
448  mcvGetPatch(ov->image[s], pv->preprocessed, int(pv->point2d->u), int(pv->point2d->v));
449  }
450 }
451 
453 {
454  for(int y = 0; y < image->height; y++)
455  {
456  unsigned char * line = (unsigned char *)(image->imageData + y * image->widthStep);
457 
458  for(int x = 0; x < image->width; x++)
459  {
460  int p = line[x];
461 
462  p += limited_white_noise[index_white_noise];
463 
464  if (p > 255)
465  p = 255;
466  else if (p < 0)
467  p = 0;
468 
469  line[x] = (unsigned char)p;
470 
471  index_white_noise++;
472  if (index_white_noise >= prime) index_white_noise = 1 + rand() % 6;
473  }
474  }
475 }
476 
477 void affine_image_generator::replace_by_noise(IplImage * image, int value)
478 {
479  for(int y = 0; y < image->height; y++)
480  {
481  unsigned char * row = mcvRow(image, y, unsigned char);
482 
483  for(int x = 0; x < image->width; x++)
484  if (int(row[x]) == value)
485  {
486  row[x] = white_noise[index_white_noise];
487  index_white_noise++;
488  if (index_white_noise >= prime) index_white_noise = 1 + rand() % 6;
489  }
490  }
491 }
492 
494 {
495  CvMat A = cvMat(2, 3, CV_32F, a);
496 
497  cvSet(affine_image, cvScalar(128));
498 
499 #if 0
500  cvGetQuadrangleSubPix(processed_original_image, affine_image, &A);
501 #else
502  float w = -(affine_image->width-1)/2;
503  float h = -(affine_image->height-1)/2;
504  float sa[9];
505  memcpy(sa,a,9*sizeof(float));
506  a[2] += w*a[0] +h*a[1];
507  a[5] += w*a[3] +h*a[4];
508  cvWarpAffine(processed_original_image, affine_image, &A,CV_INTER_LINEAR+CV_WARP_INVERSE_MAP);
509  memcpy(a,sa,9*sizeof(float));
510 #endif
511 
512  if (use_random_background)
513  replace_by_noise(affine_image, 128);
514  else
515  mcvReplace(affine_image, 128, (int)128);
516 
517  if (add_gaussian_smoothing)
518  {
519  if (rand() % 3 == 0)
520  {
521  int aperture = 3 + 2 * (rand() % 3);
522  cvSmooth(affine_image, affine_image, CV_GAUSSIAN, aperture, aperture);
523  }
524 
525  if (change_intensities)
526  cvCvtScale(affine_image, affine_image, rand(0.8f, 1.2f), rand(-10.f, 10.f));
527 
528  if (noise_level > 0)
529  add_white_noise(affine_image);
530 
531  if (0)
532  {
533  static int n = 0;
534  mcvSaveImage("affine%04d.bmp", n, affine_image);
535  n++;
536  }
537  }
538 }
539 
541 {
542  generate_affine_image();
543 
544  smoothed_generated_object_view->build(affine_image, gaussian_smoothing_kernel_size);
545 }
546 
547 vector<image_class_example *> * affine_image_generator::generate_random_examples(void)
548 {
549  generate_random_affine_transformation();
550  generate_object_view();
551 
552  vector<image_class_example *> * result = new vector<image_class_example *>;
553 
554  for(int i = 0; i < point_number; i++)
555  {
556  object_keypoint * kp = &(used_keypoint_array[i]);
557  int scale = int(kp->scale);
558  IplImage * im = smoothed_generated_object_view->image[scale];
559  float nu, nv;
560 
561  affine_transformation(PyrImage::convCoordf(float(kp->M[0]), scale, 0),
562  PyrImage::convCoordf(float(kp->M[1]), scale, 0),
563  nu, nv);
564 
565  nu = PyrImage::convCoordf(nu, 0, scale) + localization_noise * rand_m1p1();
566  nv = PyrImage::convCoordf(nv, 0, scale) + localization_noise * rand_m1p1();
567 
568  if ((int)nu > patch_size && (int)nu < im->width - patch_size &&
569  (int)nv > patch_size && (int)nv < im->height - patch_size)
570  {
572  nu, nv, (float)scale,
573  smoothed_generated_object_view,
574  patch_size);
575  pv->orig_u = float(kp->M[0]);
576  pv->orig_v = float(kp->M[1]);
577 
578  preprocess_point_view(pv, smoothed_generated_object_view);
579 
580  result->push_back(pv);
581  point_views.push_back(pv);
582  }
583  }
584 
585  return result;
586 }
587 
589 {
590  for(vector<object_view *>::iterator ov_it = generated_object_views_for_learning.begin();
591  ov_it < generated_object_views_for_learning.end();
592  ov_it++)
593  {
594  delete *ov_it;
595  }
596 
597  generated_object_views_for_learning.clear();
598 
599  for(vector<image_class_example *>::iterator pv_it = point_views.begin();
600  pv_it < point_views.end();
601  pv_it++)
602  {
603  delete *pv_it;
604  }
605 
606  point_views.clear();
607 }