bazar  1.3.1
keypoint_orientation_corrector.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 <iostream>
22 #include <cmath>
23 using namespace std;
24 
25 #include <starter.h>
27 
28 const short ACTUAL_MAX_GRADIENT = 1024;
29 const unsigned short GRADIENT_SHIFT = 2;
31 
32 #define ATAN2_TABLE_INDEX(dx, dy) (((dy + MAX_GRADIENT) * (2 * MAX_GRADIENT + 1)) + (dx + MAX_GRADIENT))
33 
34 const short MINIMAL_NORM = 0; // of the gradient to be taken into account
35 
36 #define DERIVATIVES_KERNEL_SIZE 1
37 
39 
40 keypoint_orientation_corrector::keypoint_orientation_corrector(int _width, int _height, int _neighborhood_size, int _nbLev)
41 {
42  width = _width;
43  height = _height;
44  neighborhood_size = _neighborhood_size;
45  nbLev = _nbLev;
46 
47  actual_neighborhood_size = neighborhood_size;
48 
49  angle_buckets = new int[ANGLE_BUCKET_NUMBER];
50 
51  initialize_tables();
52 }
53 
54 void keypoint_orientation_corrector::initialize_tables(void)
55 {
56  atan2_table = new short[(2 * MAX_GRADIENT + 1) * (2 * MAX_GRADIENT + 1)];
57 
58  for(int dy = -MAX_GRADIENT; dy <= +MAX_GRADIENT; dy++)
59  for(int dx = -MAX_GRADIENT; dx <= +MAX_GRADIENT; dx++)
60  {
61  int index = ATAN2_TABLE_INDEX(dx, dy);
62  float norm2 = float(dx * dx + dy * dy);
63  if (norm2 > MINIMAL_NORM * MINIMAL_NORM)
64  {
65  float angle = atan2((float)dy, (float)dx);
66  angle = (float) ((angle + 3.14159) * 180 / 3.14159);
67  if (angle < 0) angle = 0;
68  if (angle > 359) angle = 359;
69  int result = int(angle / ANGLE_QUANTUM + 0.5);
70  if (result < 0) result = 0;
71  if (result >= ANGLE_BUCKET_NUMBER) result = ANGLE_BUCKET_NUMBER - 1;
72  atan2_table[index] = (short)result;
73  }
74  else
75  atan2_table[index] = -1;
76  }
77 
78  orientation_lookup_tables = new int* [ANGLE_BUCKET_NUMBER*nbLev];
79 
80  // this image is used only to know widthStep for each level. TODO: cleanme.
81  PyrImage im(cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1), nbLev);
82 
83  for(int i = 0; i < ANGLE_BUCKET_NUMBER*nbLev; i++)
84  {
85  int level = i / ANGLE_BUCKET_NUMBER;
86  int angle = i % ANGLE_BUCKET_NUMBER;
87  int size = neighborhood_size /*>> (level)*/;
88  int * table = orientation_lookup_tables[i] = new int[size * size];
89  float cs = float(cos(angle * 2 * 3.14159 / ANGLE_BUCKET_NUMBER));
90  float sn = float(sin(angle * 2 * 3.14159 / ANGLE_BUCKET_NUMBER));
91  float c = size / 2.f;
92  for(int y = 0; y < size; y++)
93  for(int x = 0; x < size; x++)
94  {
95  float dx = x - c;
96  float dy = y - c;
97 
98  int nx = int(cs * dx - sn * dy + 0.5);
99  int ny = int(sn * dx + cs * dy + 0.5);
100  table[y * size + x] = int(ny * im[level]->widthStep + nx);
101  }
102  }
103 
104  exp_weights = cvCreateImage(cvSize(neighborhood_size, neighborhood_size), IPL_DEPTH_32S, 1);
105 
106  // should test ACTUAL_NEIGHBORHOOD_SIZE here (ie where the first non nul weight appears)
107  bool actual_neighborhood_size_found = false;
108  for(int y = 0; y < neighborhood_size; y++)
109  {
110  int * W = (int *)(exp_weights->imageData + y * exp_weights->widthStep);
111 
112  for(int x = 0; x < neighborhood_size; x++)
113  {
114  float d2 = float(gf_sqr(x - neighborhood_size / 2) + gf_sqr(y - neighborhood_size / 2));
115  float sigma_d2 = 5;
116 
117  W[x] = int(100 * exp(-d2 / (2 * sigma_d2 * sigma_d2)));
118 
119  if (y == neighborhood_size / 2)
120  if (x > neighborhood_size / 2 && !actual_neighborhood_size_found)
121  if (W[x] == 0)
122  {
123  actual_neighborhood_size = 2 * (x - (neighborhood_size / 2));
124  actual_neighborhood_size_found = true;
125  }
126  }
127  }
128 }
129 
131 {
132  delete[] angle_buckets;
133 
134  for(int i = 0; i < ANGLE_BUCKET_NUMBER*nbLev; i++)
135  delete[] orientation_lookup_tables[i];
136  delete[] orientation_lookup_tables;
137  if (atan2_table) delete[] atan2_table;
138 }
139 
140 void keypoint_orientation_corrector::compute_gradient_images(IplImage * image, IplImage ** _Ix, IplImage ** _Iy)
141 {
142  *_Ix = cvCreateImage(cvSize(image->width, image->height), IPL_DEPTH_16S, 1);
143  *_Iy = cvCreateImage(cvSize(image->width, image->height), IPL_DEPTH_16S, 1);
144 
145  cvSobel(image, *_Ix, 1, 0, DERIVATIVES_KERNEL_SIZE);
146  cvSobel(image, *_Iy, 0, 1, DERIVATIVES_KERNEL_SIZE);
147 }
148 
149 int keypoint_orientation_corrector::orientation_bucket_index(const IplImage * _Ix, const IplImage * _Iy,
150  const int u, const int v)
151 {
152  const int D = actual_neighborhood_size / 2;
153 
154  for(int i = 0; i < ANGLE_BUCKET_NUMBER; i++)
155  angle_buckets[i] = 0;
156 
157  for(int y = -D; y < D; y++)
158  {
159  int dIx = (v + y) * _Ix->widthStep + (u << 1);
160  short * Ix_row = (short*)(_Ix->imageData + dIx);
161  short * Iy_row = (short*)(_Iy->imageData + dIx);
162  int * W = (int*) (exp_weights->imageData + (D + y) * exp_weights->widthStep) + D;
163 
164  for(int x = -D; x < D; x++)
165  {
166  if (W[x] == 0) continue;
167 
168  int dx = Ix_row[x] >> GRADIENT_SHIFT;
169  int dy = Iy_row[x] >> GRADIENT_SHIFT;
170  int norm2 = dx * dx + dy * dy;
171 
172  if (dx <= -MAX_GRADIENT) dx = -MAX_GRADIENT + 1;
173  else if (dx >= MAX_GRADIENT) dx = MAX_GRADIENT - 1;
174  if (dy <= -MAX_GRADIENT) dy = -MAX_GRADIENT + 1;
175  else if (dy >= MAX_GRADIENT) dy = MAX_GRADIENT - 1;
176 
177  int index = atan2_table[ATAN2_TABLE_INDEX(dx, dy)];
178  assert(index <ANGLE_BUCKET_NUMBER);
179  angle_buckets[index] += W[x] * norm2;
180  }
181  }
182 
183  // Here Lowe smoothes the angle_buckets histogram for a more robust estimation of the orientation
184  // He also fits a parabola to refine the orientation. Not required in our method thanks to the classifier.
185 
186  int orientation_bucket_index = 0, value = angle_buckets[0];
187  for(int i = 1; i < ANGLE_BUCKET_NUMBER; i++)
188  if (angle_buckets[i] > value)
189  {
190  value = angle_buckets[i];
191  orientation_bucket_index = i;
192  }
193 
194  return orientation_bucket_index;
195 }
196 
197 int keypoint_orientation_corrector::optimized_orientation_bucket_index(const IplImage * _Ix, const IplImage * _Iy,
198  const int u, const int v)
199 {
200  const int D = actual_neighborhood_size / 2;
201 
202  for(int i = 0; i < ANGLE_BUCKET_NUMBER; i++)
203  angle_buckets[i] = 0;
204 
205  for(int y = -D; y < D; y++)
206  {
207  int dIx = (v + y) * _Ix->widthStep + (u << 1);
208  short * Ix_row = (short*)(_Ix->imageData + dIx);
209  short * Iy_row = (short*)(_Iy->imageData + dIx);
210  int * W = (int*) (exp_weights->imageData + (D + y) * exp_weights->widthStep) + D;
211 
212  int dx = (y + D) & 1;
213 
214  for(int x = dx; x < D; x+=2)
215  {
216  if (W[x] == 0) break;
217 
218  int dx = Ix_row[x] >> GRADIENT_SHIFT;
219  int dy = Iy_row[x] >> GRADIENT_SHIFT;
220  int norm2 = dx * dx + dy * dy;
221 
222  if (dx <= -MAX_GRADIENT) dx = -MAX_GRADIENT + 1;
223  else if (dx >= MAX_GRADIENT) dx = MAX_GRADIENT - 1;
224  if (dy <= -MAX_GRADIENT) dy = -MAX_GRADIENT + 1;
225  else if (dy >= MAX_GRADIENT) dy = MAX_GRADIENT - 1;
226 
227  short index = atan2_table[ATAN2_TABLE_INDEX(dx, dy)];
228  angle_buckets[index] += W[x] * norm2;
229  }
230 
231  for(int x = -2 + dx; x >= -D; x-=2)
232  {
233  if (W[x] == 0) break;
234 
235  int dx = Ix_row[x] >> GRADIENT_SHIFT;
236  int dy = Iy_row[x] >> GRADIENT_SHIFT;
237  int norm2 = dx * dx + dy * dy;
238 
239  if (dx <= -MAX_GRADIENT) dx = -MAX_GRADIENT + 1;
240  else if (dx >= MAX_GRADIENT) dx = MAX_GRADIENT - 1;
241  if (dy <= -MAX_GRADIENT) dy = -MAX_GRADIENT + 1;
242  else if (dy >= MAX_GRADIENT) dy = MAX_GRADIENT - 1;
243 
244  short index = atan2_table[ATAN2_TABLE_INDEX(dx, dy)];
245  angle_buckets[index] += W[x] * norm2;
246  }
247  }
248 
249  // Here Lowe smoothes the angle_buckets histogram for a more robust estimation of the orientation
250  // He also fits a parabola to refine the orientation. Not required in our method thanks to the classifier.
251 
252  int orientation_bucket_index = 0, value = angle_buckets[0];
253  for(int i = 1; i < ANGLE_BUCKET_NUMBER; i++)
254  if (angle_buckets[i] > value)
255  {
256  value = angle_buckets[i];
257  orientation_bucket_index = i;
258  }
259 
260  return orientation_bucket_index;
261 }
262 
263 void keypoint_orientation_corrector::rotate_patchf(IplImage * original_image, float u, float v,
264  IplImage * rotated_patch,
265  float angle)
266 {
267  static float m[6];
268  static CvMat M = cvMat( 2, 3, CV_32F, m );
269 
270  m[0] = (float)(cos(-angle));
271  m[1] = (float)(sin(-angle));
272  m[2] = u;
273  m[3] = -m[1];
274  m[4] = m[0];
275  m[5] = v;
276 
277  cvGetQuadrangleSubPix(original_image, rotated_patch, &M);
278 }
279 
280 void keypoint_orientation_corrector::rotate_patch(IplImage * original_image, int u, int v,
281  IplImage * rotated_patch,
282  int orientation_bucket_index, int level)
283 {
284  if (original_image->depth == IPL_DEPTH_8U && rotated_patch->depth == IPL_DEPTH_8U)
285  {
286  int * table = orientation_lookup_tables[level * ANGLE_BUCKET_NUMBER + orientation_bucket_index];
287  char * src = original_image->imageData;
288  int offset = (int)v * original_image->widthStep + (int)u;
289  unsigned max = (unsigned)original_image->widthStep*(original_image->height+1);
290  char * dst = rotated_patch->imageData;
291 
292  const int length = neighborhood_size * neighborhood_size;
293  for(int i = 0; i < length; i++) {
294  unsigned idx = offset + table[i];
295  if (idx < max)
296  dst[i] = src[idx];
297  }
298  }
299  else if (original_image->depth == (int)IPL_DEPTH_16S && rotated_patch->depth == (int)IPL_DEPTH_16S)
300  {
301  int * table = orientation_lookup_tables[level* ANGLE_BUCKET_NUMBER + orientation_bucket_index];
302  short * src = (short*)(original_image->imageData + (int)v * original_image->widthStep) + (int)u;
303  short * dst = (short*)(rotated_patch->imageData);
304 
305  const int length = neighborhood_size * neighborhood_size;
306  for(int i = 0; i < length; i++)
307  dst[i] = src[table[i]];
308  }
309  else
310  {
311  cerr << "keypoint_orientation_corrector::rotate_patch invalid depths" << endl;
312  cerr << "depth 1 = " << original_image->depth << endl;
313  cerr << "depth 2 = " << rotated_patch->depth << endl;
314  }
315 }
316 
318  IplImage * _Ix, IplImage * _Iy)
319 {
320  // Avoid a warning:
321  image = 0;
322 
323  int _orientation_bucket_index = orientation_bucket_index(_Ix, _Iy, u, v);
324 
325  return _orientation_bucket_index * 2 * 3.14159f / ANGLE_BUCKET_NUMBER;
326 }
327 
328 int keypoint_orientation_corrector::correct_orientation(IplImage * image, int u, int v,
329  IplImage * rotated_neighborhood,
330  IplImage * _Ix, IplImage * _Iy, int level)
331 {
332  int _orientation_bucket_index = orientation_bucket_index(_Ix, _Iy, u, v);
333 
334  rotate_patch(image, u, v, rotated_neighborhood, _orientation_bucket_index, level);
335 
336  return _orientation_bucket_index;
337 }
338 
339 int keypoint_orientation_corrector::correct_orientationf(IplImage * image, float u, float v,
340  IplImage * rotated_neighborhood,
341  float orientation_in_radians, int level)
342 {
343  if (subpixel_rotate)
344  rotate_patchf(image, u, v, rotated_neighborhood, orientation_in_radians);
345  else {
346  int _orientation_bucket_index = int(orientation_in_radians * ANGLE_BUCKET_NUMBER / (2 * 3.14159));
347  if (_orientation_bucket_index < 0) _orientation_bucket_index = 0;
348  if (_orientation_bucket_index >= ANGLE_BUCKET_NUMBER) _orientation_bucket_index = ANGLE_BUCKET_NUMBER - 1;
349  rotate_patch(image, (int)(u+.5f), (int)(v+.5f), rotated_neighborhood, _orientation_bucket_index, level);
350  }
351 
352  return 0;
353 }
354