MRPT  1.9.9
CDifodo.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "vision-precomp.h" // Precompiled headers
11 
12 #include <mrpt/vision/CDifodo.h>
13 #include <mrpt/system/CTicTac.h>
14 #include <mrpt/core/round.h>
15 
16 using namespace mrpt;
17 using namespace mrpt::vision;
18 using namespace mrpt::math;
19 using namespace std;
20 using namespace Eigen;
21 using mrpt::round;
22 using mrpt::square;
23 
25 {
26  rows = 60;
27  cols = 80;
28  fovh = M_PIf * 58.6f / 180.0f;
29  fovv = M_PIf * 45.6f / 180.0f;
30  cam_mode = 1; // (1 - 640 x 480, 2 - 320 x 240, 4 - 160 x 120)
31  downsample = 1;
32  ctf_levels = 1;
33  width = 640 / (cam_mode * downsample);
34  height = 480 / (cam_mode * downsample);
35  fast_pyramid = true;
36 
37  // Resize pyramid
38  const unsigned int pyr_levels =
39  round(log(float(width / cols)) / log(2.f)) + ctf_levels;
40  depth.resize(pyr_levels);
41  depth_old.resize(pyr_levels);
42  depth_inter.resize(pyr_levels);
43  depth_warped.resize(pyr_levels);
44  xx.resize(pyr_levels);
45  xx_inter.resize(pyr_levels);
46  xx_old.resize(pyr_levels);
47  xx_warped.resize(pyr_levels);
48  yy.resize(pyr_levels);
49  yy_inter.resize(pyr_levels);
50  yy_old.resize(pyr_levels);
51  yy_warped.resize(pyr_levels);
52  transformations.resize(pyr_levels);
53 
54  for (unsigned int i = 0; i < pyr_levels; i++)
55  {
56  unsigned int s = pow(2.f, int(i));
57  cols_i = width / s;
58  rows_i = height / s;
59  depth[i].resize(rows_i, cols_i);
60  depth_inter[i].resize(rows_i, cols_i);
61  depth_old[i].resize(rows_i, cols_i);
62  depth[i].assign(0.0f);
63  depth_old[i].assign(0.0f);
64  xx[i].resize(rows_i, cols_i);
65  xx_inter[i].resize(rows_i, cols_i);
66  xx_old[i].resize(rows_i, cols_i);
67  xx[i].assign(0.0f);
68  xx_old[i].assign(0.0f);
69  yy[i].resize(rows_i, cols_i);
70  yy_inter[i].resize(rows_i, cols_i);
71  yy_old[i].resize(rows_i, cols_i);
72  yy[i].assign(0.0f);
73  yy_old[i].assign(0.0f);
74  transformations[i].resize(4, 4);
75 
76  if (cols_i <= cols)
77  {
78  depth_warped[i].resize(rows_i, cols_i);
79  xx_warped[i].resize(rows_i, cols_i);
80  yy_warped[i].resize(rows_i, cols_i);
81  }
82  }
83 
84  depth_wf.setSize(height, width);
85 
86  fps = 30.f; // In Hz
87 
88  previous_speed_const_weight = 0.05f;
89  previous_speed_eig_weight = 0.5f;
90  kai_loc_old.assign(0.f);
91  num_valid_points = 0;
92 
93  // Compute gaussian mask
94  VectorXf v_mask(4);
95  v_mask(0) = 1.f;
96  v_mask(1) = 2.f;
97  v_mask(2) = 2.f;
98  v_mask(3) = 1.f;
99  for (unsigned int i = 0; i < 4; i++)
100  for (unsigned int j = 0; j < 4; j++)
101  f_mask(i, j) = v_mask(i) * v_mask(j) / 36.f;
102 
103  // Compute gaussian mask
104  float v_mask2[5] = {1, 4, 6, 4, 1};
105  for (unsigned int i = 0; i < 5; i++)
106  for (unsigned int j = 0; j < 5; j++)
107  g_mask[i][j] = v_mask2[i] * v_mask2[j] / 256.f;
108 }
109 
111 {
112  const float max_depth_dif = 0.1f;
113 
114  // Push coordinates back
115  depth_old.swap(depth);
116  xx_old.swap(xx);
117  yy_old.swap(yy);
118 
119  // The number of levels of the pyramid does not match the number of levels
120  // used
121  // in the odometry computation (because we might want to finish with lower
122  // resolutions)
123 
124  unsigned int pyr_levels =
125  round(log(float(width / cols)) / log(2.f)) + ctf_levels;
126 
127  // Generate levels
128  for (unsigned int i = 0; i < pyr_levels; i++)
129  {
130  unsigned int s = pow(2.f, int(i));
131  cols_i = width / s;
132  rows_i = height / s;
133  const int rows_i2 = 2 * rows_i;
134  const int cols_i2 = 2 * cols_i;
135  const int i_1 = i - 1;
136 
137  if (i == 0) depth[i].swap(depth_wf);
138 
139  // Downsampling
140  //-----------------------------------------------------------------------------
141  else
142  {
143  for (unsigned int u = 0; u < cols_i; u++)
144  for (unsigned int v = 0; v < rows_i; v++)
145  {
146  const int u2 = 2 * u;
147  const int v2 = 2 * v;
148  const float dcenter = depth[i_1](v2, u2);
149 
150  // Inner pixels
151  if ((v > 0) && (v < rows_i - 1) && (u > 0) &&
152  (u < cols_i - 1))
153  {
154  if (dcenter > 0.f)
155  {
156  float sum = 0.f;
157  float weight = 0.f;
158 
159  for (int l = -2; l < 3; l++)
160  for (int k = -2; k < 3; k++)
161  {
162  const float abs_dif = abs(
163  depth[i_1](v2 + k, u2 + l) - dcenter);
164  if (abs_dif < max_depth_dif)
165  {
166  const float aux_w =
167  g_mask[2 + k][2 + l] *
168  (max_depth_dif - abs_dif);
169  weight += aux_w;
170  sum +=
171  aux_w * depth[i_1](v2 + k, u2 + l);
172  }
173  }
174  depth[i](v, u) = sum / weight;
175  }
176  else
177  {
178  float min_depth = 10.f;
179  for (int l = -2; l < 3; l++)
180  for (int k = -2; k < 3; k++)
181  {
182  const float d = depth[i_1](v2 + k, u2 + l);
183  if ((d > 0.f) && (d < min_depth))
184  min_depth = d;
185  }
186 
187  if (min_depth < 10.f)
188  depth[i](v, u) = min_depth;
189  else
190  depth[i](v, u) = 0.f;
191  }
192  }
193 
194  // Boundary
195  else
196  {
197  if (dcenter > 0.f)
198  {
199  float sum = 0.f;
200  float weight = 0.f;
201 
202  for (int l = -2; l < 3; l++)
203  for (int k = -2; k < 3; k++)
204  {
205  const int indv = v2 + k, indu = u2 + l;
206  if ((indv >= 0) && (indv < rows_i2) &&
207  (indu >= 0) && (indu < cols_i2))
208  {
209  const float abs_dif = abs(
210  depth[i_1](indv, indu) - dcenter);
211  if (abs_dif < max_depth_dif)
212  {
213  const float aux_w =
214  g_mask[2 + k][2 + l] *
215  (max_depth_dif - abs_dif);
216  weight += aux_w;
217  sum +=
218  aux_w * depth[i_1](indv, indu);
219  }
220  }
221  }
222  depth[i](v, u) = sum / weight;
223  }
224  else
225  {
226  float min_depth = 10.f;
227  for (int l = -2; l < 3; l++)
228  for (int k = -2; k < 3; k++)
229  {
230  const int indv = v2 + k, indu = u2 + l;
231  if ((indv >= 0) && (indv < rows_i2) &&
232  (indu >= 0) && (indu < cols_i2))
233  {
234  const float d = depth[i_1](indv, indu);
235  if ((d > 0.f) && (d < min_depth))
236  min_depth = d;
237  }
238  }
239 
240  if (min_depth < 10.f)
241  depth[i](v, u) = min_depth;
242  else
243  depth[i](v, u) = 0.f;
244  }
245  }
246  }
247  }
248 
249  // Calculate coordinates "xy" of the points
250  const float inv_f_i = 2.f * tan(0.5f * fovh) / float(cols_i);
251  const float disp_u_i = 0.5f * (cols_i - 1);
252  const float disp_v_i = 0.5f * (rows_i - 1);
253 
254  for (unsigned int u = 0; u < cols_i; u++)
255  for (unsigned int v = 0; v < rows_i; v++)
256  if (depth[i](v, u) > 0.f)
257  {
258  xx[i](v, u) = (u - disp_u_i) * depth[i](v, u) * inv_f_i;
259  yy[i](v, u) = (v - disp_v_i) * depth[i](v, u) * inv_f_i;
260  }
261  else
262  {
263  xx[i](v, u) = 0.f;
264  yy[i](v, u) = 0.f;
265  }
266  }
267 }
268 
270 {
271  const float max_depth_dif = 0.1f;
272 
273  // Push coordinates back
274  depth_old.swap(depth);
275  xx_old.swap(xx);
276  yy_old.swap(yy);
277 
278  // The number of levels of the pyramid does not match the number of levels
279  // used
280  // in the odometry computation (because we might want to finish with lower
281  // resolutions)
282 
283  unsigned int pyr_levels =
284  round(log(float(width / cols)) / log(2.f)) + ctf_levels;
285 
286  // Generate levels
287  for (unsigned int i = 0; i < pyr_levels; i++)
288  {
289  unsigned int s = pow(2.f, int(i));
290  cols_i = width / s;
291  rows_i = height / s;
292  // const int rows_i2 = 2*rows_i;
293  // const int cols_i2 = 2*cols_i;
294  const int i_1 = i - 1;
295 
296  if (i == 0) depth[i].swap(depth_wf);
297 
298  // Downsampling
299  //-----------------------------------------------------------------------------
300  else
301  {
302  for (unsigned int u = 0; u < cols_i; u++)
303  for (unsigned int v = 0; v < rows_i; v++)
304  {
305  const int u2 = 2 * u;
306  const int v2 = 2 * v;
307 
308  // Inner pixels
309  if ((v > 0) && (v < rows_i - 1) && (u > 0) &&
310  (u < cols_i - 1))
311  {
312  const Matrix4f d_block =
313  depth[i_1].block<4, 4>(v2 - 1, u2 - 1);
314  float depths[4] = {d_block(5), d_block(6), d_block(9),
315  d_block(10)};
316  float dcenter;
317 
318  // Sort the array (try to find a good/representative
319  // value)
320  for (signed char k = 2; k >= 0; k--)
321  if (depths[k + 1] < depths[k])
322  std::swap(depths[k + 1], depths[k]);
323  for (unsigned char k = 1; k < 3; k++)
324  if (depths[k] > depths[k + 1])
325  std::swap(depths[k + 1], depths[k]);
326  if (depths[2] < depths[1])
327  dcenter = depths[1];
328  else
329  dcenter = depths[2];
330 
331  if (dcenter > 0.f)
332  {
333  float sum = 0.f;
334  float weight = 0.f;
335 
336  for (unsigned char k = 0; k < 16; k++)
337  {
338  const float abs_dif = abs(d_block(k) - dcenter);
339  if (abs_dif < max_depth_dif)
340  {
341  const float aux_w =
342  f_mask(k) * (max_depth_dif - abs_dif);
343  weight += aux_w;
344  sum += aux_w * d_block(k);
345  }
346  }
347  depth[i](v, u) = sum / weight;
348  }
349  else
350  depth[i](v, u) = 0.f;
351  }
352 
353  // Boundary
354  else
355  {
356  const Matrix2f d_block = depth[i_1].block<2, 2>(v2, u2);
357  const float new_d = 0.25f * d_block.sumAll();
358  if (new_d < 0.4f)
359  depth[i](v, u) = 0.f;
360  else
361  depth[i](v, u) = new_d;
362  }
363  }
364  }
365 
366  // Calculate coordinates "xy" of the points
367  const float inv_f_i = 2.f * tan(0.5f * fovh) / float(cols_i);
368  const float disp_u_i = 0.5f * (cols_i - 1);
369  const float disp_v_i = 0.5f * (rows_i - 1);
370 
371  for (unsigned int u = 0; u < cols_i; u++)
372  for (unsigned int v = 0; v < rows_i; v++)
373  if (depth[i](v, u) > 0.f)
374  {
375  xx[i](v, u) = (u - disp_u_i) * depth[i](v, u) * inv_f_i;
376  yy[i](v, u) = (v - disp_v_i) * depth[i](v, u) * inv_f_i;
377  }
378  else
379  {
380  xx[i](v, u) = 0.f;
381  yy[i](v, u) = 0.f;
382  }
383  }
384 }
385 
387 {
388  // Camera parameters (which also depend on the level resolution)
389  const float f = float(cols_i) / (2.f * tan(0.5f * fovh));
390  const float disp_u_i = 0.5f * float(cols_i - 1);
391  const float disp_v_i = 0.5f * float(rows_i - 1);
392 
393  // Rigid transformation estimated up to the present level
394  Matrix4f acu_trans;
395  acu_trans.setIdentity();
396  for (unsigned int i = 1; i <= level; i++)
397  acu_trans = transformations[i - 1] * acu_trans;
398 
399  MatrixXf wacu(rows_i, cols_i);
400  wacu.assign(0.f);
401  depth_warped[image_level].assign(0.f);
402 
403  const float cols_lim = float(cols_i - 1);
404  const float rows_lim = float(rows_i - 1);
405 
406  // Warping loop
407  //---------------------------------------------------------
408  for (unsigned int j = 0; j < cols_i; j++)
409  for (unsigned int i = 0; i < rows_i; i++)
410  {
411  const float z = depth[image_level](i, j);
412 
413  if (z > 0.f)
414  {
415  // Transform point to the warped reference frame
416  const float depth_w = acu_trans(0, 0) * z +
417  acu_trans(0, 1) * xx[image_level](i, j) +
418  acu_trans(0, 2) * yy[image_level](i, j) +
419  acu_trans(0, 3);
420  const float x_w = acu_trans(1, 0) * z +
421  acu_trans(1, 1) * xx[image_level](i, j) +
422  acu_trans(1, 2) * yy[image_level](i, j) +
423  acu_trans(1, 3);
424  const float y_w = acu_trans(2, 0) * z +
425  acu_trans(2, 1) * xx[image_level](i, j) +
426  acu_trans(2, 2) * yy[image_level](i, j) +
427  acu_trans(2, 3);
428 
429  // Calculate warping
430  const float uwarp = f * x_w / depth_w + disp_u_i;
431  const float vwarp = f * y_w / depth_w + disp_v_i;
432 
433  // The warped pixel (which is not integer in general)
434  // contributes to all the surrounding ones
435  if ((uwarp >= 0.f) && (uwarp < cols_lim) && (vwarp >= 0.f) &&
436  (vwarp < rows_lim))
437  {
438  const int uwarp_l = uwarp;
439  const int uwarp_r = uwarp_l + 1;
440  const int vwarp_d = vwarp;
441  const int vwarp_u = vwarp_d + 1;
442  const float delta_r = float(uwarp_r) - uwarp;
443  const float delta_l = uwarp - float(uwarp_l);
444  const float delta_u = float(vwarp_u) - vwarp;
445  const float delta_d = vwarp - float(vwarp_d);
446 
447  // Warped pixel very close to an integer value
448  if (abs(round(uwarp) - uwarp) + abs(round(vwarp) - vwarp) <
449  0.05f)
450  {
451  depth_warped[image_level](round(vwarp), round(uwarp)) +=
452  depth_w;
453  wacu(round(vwarp), round(uwarp)) += 1.f;
454  }
455  else
456  {
457  const float w_ur = square(delta_l) + square(delta_d);
458  depth_warped[image_level](vwarp_u, uwarp_r) +=
459  w_ur * depth_w;
460  wacu(vwarp_u, uwarp_r) += w_ur;
461 
462  const float w_ul = square(delta_r) + square(delta_d);
463  depth_warped[image_level](vwarp_u, uwarp_l) +=
464  w_ul * depth_w;
465  wacu(vwarp_u, uwarp_l) += w_ul;
466 
467  const float w_dr = square(delta_l) + square(delta_u);
468  depth_warped[image_level](vwarp_d, uwarp_r) +=
469  w_dr * depth_w;
470  wacu(vwarp_d, uwarp_r) += w_dr;
471 
472  const float w_dl = square(delta_r) + square(delta_u);
473  depth_warped[image_level](vwarp_d, uwarp_l) +=
474  w_dl * depth_w;
475  wacu(vwarp_d, uwarp_l) += w_dl;
476  }
477  }
478  }
479  }
480 
481  // Scale the averaged depth and compute spatial coordinates
482  const float inv_f_i = 1.f / f;
483  for (unsigned int u = 0; u < cols_i; u++)
484  for (unsigned int v = 0; v < rows_i; v++)
485  {
486  if (wacu(v, u) > 0.f)
487  {
488  depth_warped[image_level](v, u) /= wacu(v, u);
489  xx_warped[image_level](v, u) =
490  (u - disp_u_i) * depth_warped[image_level](v, u) * inv_f_i;
491  yy_warped[image_level](v, u) =
492  (v - disp_v_i) * depth_warped[image_level](v, u) * inv_f_i;
493  }
494  else
495  {
496  depth_warped[image_level](v, u) = 0.f;
497  xx_warped[image_level](v, u) = 0.f;
498  yy_warped[image_level](v, u) = 0.f;
499  }
500  }
501 }
502 
504 {
505  null.resize(rows_i, cols_i);
506  null.assign(false);
507  num_valid_points = 0;
508 
509  for (unsigned int u = 0; u < cols_i; u++)
510  for (unsigned int v = 0; v < rows_i; v++)
511  {
512  if ((depth_old[image_level](v, u)) == 0.f ||
513  (depth_warped[image_level](v, u) == 0.f))
514  {
515  depth_inter[image_level](v, u) = 0.f;
516  xx_inter[image_level](v, u) = 0.f;
517  yy_inter[image_level](v, u) = 0.f;
518  null(v, u) = true;
519  }
520  else
521  {
522  depth_inter[image_level](v, u) =
523  0.5f * (depth_old[image_level](v, u) +
524  depth_warped[image_level](v, u));
525  xx_inter[image_level](v, u) =
526  0.5f *
527  (xx_old[image_level](v, u) + xx_warped[image_level](v, u));
528  yy_inter[image_level](v, u) =
529  0.5f *
530  (yy_old[image_level](v, u) + yy_warped[image_level](v, u));
531  null(v, u) = false;
532  if ((u > 0) && (v > 0) && (u < cols_i - 1) && (v < rows_i - 1))
533  num_valid_points++;
534  }
535  }
536 }
537 
539 {
540  dt.resize(rows_i, cols_i);
541  dt.assign(0.f);
542  du.resize(rows_i, cols_i);
543  du.assign(0.f);
544  dv.resize(rows_i, cols_i);
545  dv.assign(0.f);
546 
547  // Compute connectivity
548  MatrixXf rx_ninv(rows_i, cols_i);
549  MatrixXf ry_ninv(rows_i, cols_i);
550  rx_ninv.assign(1.f);
551  ry_ninv.assign(1.f);
552 
553  for (unsigned int u = 0; u < cols_i - 1; u++)
554  for (unsigned int v = 0; v < rows_i; v++)
555  if (null(v, u) == false)
556  {
557  rx_ninv(v, u) = sqrtf(
558  square(
559  xx_inter[image_level](v, u + 1) -
560  xx_inter[image_level](v, u)) +
561  square(
562  depth_inter[image_level](v, u + 1) -
563  depth_inter[image_level](v, u)));
564  }
565 
566  for (unsigned int u = 0; u < cols_i; u++)
567  for (unsigned int v = 0; v < rows_i - 1; v++)
568  if (null(v, u) == false)
569  {
570  ry_ninv(v, u) = sqrtf(
571  square(
572  yy_inter[image_level](v + 1, u) -
573  yy_inter[image_level](v, u)) +
574  square(
575  depth_inter[image_level](v + 1, u) -
576  depth_inter[image_level](v, u)));
577  }
578 
579  // Spatial derivatives
580  for (unsigned int v = 0; v < rows_i; v++)
581  {
582  for (unsigned int u = 1; u < cols_i - 1; u++)
583  if (null(v, u) == false)
584  du(v, u) =
585  (rx_ninv(v, u - 1) * (depth_inter[image_level](v, u + 1) -
586  depth_inter[image_level](v, u)) +
587  rx_ninv(v, u) * (depth_inter[image_level](v, u) -
588  depth_inter[image_level](v, u - 1))) /
589  (rx_ninv(v, u) + rx_ninv(v, u - 1));
590 
591  du(v, 0) = du(v, 1);
592  du(v, cols_i - 1) = du(v, cols_i - 2);
593  }
594 
595  for (unsigned int u = 0; u < cols_i; u++)
596  {
597  for (unsigned int v = 1; v < rows_i - 1; v++)
598  if (null(v, u) == false)
599  dv(v, u) =
600  (ry_ninv(v - 1, u) * (depth_inter[image_level](v + 1, u) -
601  depth_inter[image_level](v, u)) +
602  ry_ninv(v, u) * (depth_inter[image_level](v, u) -
603  depth_inter[image_level](v - 1, u))) /
604  (ry_ninv(v, u) + ry_ninv(v - 1, u));
605 
606  dv(0, u) = dv(1, u);
607  dv(rows_i - 1, u) = dv(rows_i - 2, u);
608  }
609 
610  // Temporal derivative
611  for (unsigned int u = 0; u < cols_i; u++)
612  for (unsigned int v = 0; v < rows_i; v++)
613  if (null(v, u) == false)
614  dt(v, u) = fps * (depth_warped[image_level](v, u) -
615  depth_old[image_level](v, u));
616 }
617 
619 {
620  weights.resize(rows_i, cols_i);
621  weights.assign(0.f);
622 
623  // Obtain the velocity associated to the rigid transformation estimated up
624  // to the present level
625  Matrix<float, 6, 1> kai_level = kai_loc_old;
626 
627  Matrix4f acu_trans;
628  acu_trans.setIdentity();
629  for (unsigned int i = 0; i < level; i++)
630  acu_trans = transformations[i] * acu_trans;
631 
632  // Alternative way to compute the log
633  CMatrixDouble44 mat_aux = acu_trans.cast<double>();
634  poses::CPose3D aux(mat_aux);
635  CArrayDouble<6> kai_level_acu((aux.ln() * fps).matrix());
636  kai_level -= kai_level_acu.cast<float>();
637 
638  // Parameters for the measurement error
639  const float f_inv = float(cols_i) / (2.f * tan(0.5f * fovh));
640  const float kz2 = 8.122e-12f; // square(1.425e-5) / 25
641 
642  // Parameters for linearization error
643  const float kduv = 20e-5f;
644  const float kdt = kduv / square(fps);
645  const float k2dt = 5e-6f;
646  const float k2duv = 5e-6f;
647 
648  for (unsigned int u = 1; u < cols_i - 1; u++)
649  for (unsigned int v = 1; v < rows_i - 1; v++)
650  if (null(v, u) == false)
651  {
652  // Compute measurment error (simplified)
653  //-----------------------------------------------------------------------
654  const float z = depth_inter[image_level](v, u);
655  const float inv_d = 1.f / z;
656  // const float dycomp = du2(v,u)*f_inv_y*inv_d;
657  // const float dzcomp = dv2(v,u)*f_inv_z*inv_d;
658  const float z2 = z * z;
659  const float z4 = z2 * z2;
660 
661  // const float var11 = kz2*z4;
662  // const float var12 =
663  // kz2*xx_inter[image_level](v,u)*z2*depth_inter[image_level](v,u);
664  // const float var13 =
665  // kz2*yy_inter[image_level](v,u)*z2*depth_inter[image_level](v,u);
666  // const float var22 =
667  // kz2*square(xx_inter[image_level](v,u))*z2;
668  // const float var23 =
669  // kz2*xx_inter[image_level](v,u)*yy_inter[image_level](v,u)*z2;
670  // const float var33 =
671  // kz2*square(yy_inter[image_level](v,u))*z2;
672  const float var44 = kz2 * z4 * square(fps);
673  const float var55 = kz2 * z4 * 0.25f;
674  const float var66 = var55;
675 
676  // const float j1 =
677  // -2.f*inv_d*inv_d*(xx_inter[image_level](v,u)*dycomp +
678  // yy_inter[image_level](v,u)*dzcomp)*(kai_level[0] +
679  // yy_inter[image_level](v,u)*kai_level[4] -
680  // xx_inter[image_level](v,u)*kai_level[5])
681  // + inv_d*dycomp*(kai_level[1] -
682  // yy_inter[image_level](v,u)*kai_level[3]) +
683  // inv_d*dzcomp*(kai_level[2] +
684  // xx_inter[image_level](v,u)*kai_level[3]);
685  // const float j2 = inv_d*dycomp*(kai_level[0] +
686  // yy_inter[image_level](v,u)*kai_level[4] -
687  // 2.f*xx_inter[image_level](v,u)*kai_level[5]) -
688  // dzcomp*kai_level[3];
689  // const float j3 = inv_d*dzcomp*(kai_level[0] +
690  // 2.f*yy_inter[image_level](v,u)*kai_level[4] -
691  // xx_inter[image_level](v,u)*kai_level[5]) +
692  // dycomp*kai_level[3];
693 
694  const float j4 = 1.f;
695  const float j5 =
696  xx_inter[image_level](v, u) * inv_d * inv_d * f_inv *
697  (kai_level[0] +
698  yy_inter[image_level](v, u) * kai_level[4] -
699  xx_inter[image_level](v, u) * kai_level[5]) +
700  inv_d * f_inv *
701  (-kai_level[1] - z * kai_level[5] +
702  yy_inter[image_level](v, u) * kai_level[3]);
703  const float j6 =
704  yy_inter[image_level](v, u) * inv_d * inv_d * f_inv *
705  (kai_level[0] +
706  yy_inter[image_level](v, u) * kai_level[4] -
707  xx_inter[image_level](v, u) * kai_level[5]) +
708  inv_d * f_inv *
709  (-kai_level[2] + z * kai_level[4] -
710  xx_inter[image_level](v, u) * kai_level[3]);
711 
712  // error_measurement(v,u) = j1*(j1*var11+j2*var12+j3*var13) +
713  // j2*(j1*var12+j2*var22+j3*var23)
714  // +j3*(j1*var13+j2*var23+j3*var33) +
715  // j4*j4*var44
716  //+
717  // j5*j5*var55 + j6*j6*var66;
718 
719  const float error_m =
720  j4 * j4 * var44 + j5 * j5 * var55 + j6 * j6 * var66;
721 
722  // Compute linearization error
723  //-----------------------------------------------------------------------
724  const float ini_du = depth_old[image_level](v, u + 1) -
725  depth_old[image_level](v, u - 1);
726  const float ini_dv = depth_old[image_level](v + 1, u) -
727  depth_old[image_level](v - 1, u);
728  const float final_du = depth_warped[image_level](v, u + 1) -
729  depth_warped[image_level](v, u - 1);
730  const float final_dv = depth_warped[image_level](v + 1, u) -
731  depth_warped[image_level](v - 1, u);
732 
733  const float dut = ini_du - final_du;
734  const float dvt = ini_dv - final_dv;
735  const float duu = du(v, u + 1) - du(v, u - 1);
736  const float dvv = dv(v + 1, u) - dv(v - 1, u);
737  const float dvu =
738  dv(v, u + 1) -
739  dv(v, u - 1); // Completely equivalent to compute duv
740 
741  const float error_l =
742  kdt * square(dt(v, u)) +
743  kduv * (square(du(v, u)) + square(dv(v, u))) +
744  k2dt * (square(dut) + square(dvt)) +
745  k2duv * (square(duu) + square(dvv) + square(dvu));
746 
747  // Weight
748  weights(v, u) = sqrt(1.f / (error_m + error_l));
749  }
750 
751  // Normalize weights in the range [0,1]
752  const float inv_max = 1.f / weights.maximum();
753  weights = inv_max * weights;
754 }
755 
757 {
758  MatrixXf A(num_valid_points, 6);
759  MatrixXf B(num_valid_points, 1);
760  unsigned int cont = 0;
761 
762  // Fill the matrix A and the vector B
763  // The order of the unknowns is (vz, vx, vy, wz, wx, wy)
764  // The points order will be (1,1), (1,2)...(1,cols-1), (2,1),
765  // (2,2)...(row-1,cols-1).
766 
767  const float f_inv = float(cols_i) / (2.f * tan(0.5f * fovh));
768 
769  for (unsigned int u = 1; u < cols_i - 1; u++)
770  for (unsigned int v = 1; v < rows_i - 1; v++)
771  if (null(v, u) == false)
772  {
773  // Precomputed expressions
774  const float d = depth_inter[image_level](v, u);
775  const float inv_d = 1.f / d;
776  const float x = xx_inter[image_level](v, u);
777  const float y = yy_inter[image_level](v, u);
778  const float dycomp = du(v, u) * f_inv * inv_d;
779  const float dzcomp = dv(v, u) * f_inv * inv_d;
780  const float tw = weights(v, u);
781 
782  // Fill the matrix A
783  A(cont, 0) =
784  tw * (1.f + dycomp * x * inv_d + dzcomp * y * inv_d);
785  A(cont, 1) = tw * (-dycomp);
786  A(cont, 2) = tw * (-dzcomp);
787  A(cont, 3) = tw * (dycomp * y - dzcomp * x);
788  A(cont, 4) = tw * (y + dycomp * inv_d * y * x +
789  dzcomp * (y * y * inv_d + d));
790  A(cont, 5) = tw * (-x - dycomp * (x * x * inv_d + d) -
791  dzcomp * inv_d * y * x);
792  B(cont, 0) = tw * (-dt(v, u));
793 
794  cont++;
795  }
796 
797  // Solve the linear system of equations using weighted least squares
798  MatrixXf AtA, AtB;
799  AtA.multiply_AtA(A);
800  AtB.multiply_AtB(A, B);
801  MatrixXf Var = AtA.ldlt().solve(AtB);
802 
803  // Covariance matrix calculation
804  MatrixXf res = -B;
805  for (unsigned int k = 0; k < 6; k++) res += Var(k) * A.col(k);
806 
807  est_cov =
808  (1.f / float(num_valid_points - 6)) * AtA.inverse() * res.squaredNorm();
809 
810  // Update last velocity in local coordinates
811  kai_loc_level = Var;
812 }
813 
815 {
816  // Clock to measure the runtime
817  mrpt::system::CTicTac clock;
818  clock.Tic();
819 
820  // Build the gaussian pyramid
821  if (fast_pyramid)
822  buildCoordinatesPyramidFast();
823  else
824  buildCoordinatesPyramid();
825 
826  // Coarse-to-fines scheme
827  for (unsigned int i = 0; i < ctf_levels; i++)
828  {
829  // Previous computations
830  transformations[i].setIdentity();
831 
832  level = i;
833  unsigned int s = pow(2.f, int(ctf_levels - (i + 1)));
834  cols_i = cols / s;
835  rows_i = rows / s;
836  image_level =
837  ctf_levels - i + round(log(float(width / cols)) / log(2.f)) - 1;
838 
839  // 1. Perform warping
840  if (i == 0)
841  {
842  depth_warped[image_level] = depth[image_level];
843  xx_warped[image_level] = xx[image_level];
844  yy_warped[image_level] = yy[image_level];
845  }
846  else
847  performWarping();
848 
849  // 2. Calculate inter coords and find null measurements
850  calculateCoord();
851 
852  // 3. Compute derivatives
853  calculateDepthDerivatives();
854 
855  // 4. Compute weights
856  computeWeights();
857 
858  // 5. Solve odometry
859  if (num_valid_points > 6) solveOneLevel();
860 
861  // 6. Filter solution
862  filterLevelSolution();
863  }
864 
865  // Update poses
866  poseUpdate();
867 
868  // Save runtime
869  execution_time = 1000.f * clock.Tac();
870 }
871 
873 {
874  // Calculate Eigenvalues and Eigenvectors
875  //----------------------------------------------------------
876  SelfAdjointEigenSolver<MatrixXf> eigensolver(est_cov);
877  if (eigensolver.info() != Success)
878  {
879  printf("\n Eigensolver couldn't find a solution. Pose is not updated");
880  return;
881  }
882 
883  // First, we have to describe both the new linear and angular velocities in
884  // the "eigenvector" basis
885  //-------------------------------------------------------------------------------------------------
886  Matrix<float, 6, 6> Bii;
887  Matrix<float, 6, 1> kai_b;
888  Bii = eigensolver.eigenvectors();
889  kai_b = Bii.colPivHouseholderQr().solve(kai_loc_level);
890 
891  // Second, we have to describe both the old linear and angular velocities in
892  // the "eigenvector" basis
893  //-------------------------------------------------------------------------------------------------
894  Matrix<float, 6, 1> kai_loc_sub = kai_loc_old;
895 
896  // Important: we have to substract the previous levels' solutions from the
897  // old velocity.
898  Matrix4f acu_trans;
899  acu_trans.setIdentity();
900  for (unsigned int i = 0; i < level; i++)
901  acu_trans = transformations[i] * acu_trans;
902 
903  CMatrixDouble44 mat_aux = acu_trans.cast<double>();
904  poses::CPose3D aux(mat_aux);
905  CArrayDouble<6> kai_level_acu(aux.ln() * fps);
906  kai_loc_sub -= kai_level_acu.cast<float>();
907 
908  // Matrix<float, 4, 4> log_trans = fps*acu_trans.log();
909  // kai_loc_sub(0) -= log_trans(0,3); kai_loc_sub(1) -= log_trans(1,3);
910  // kai_loc_sub(2) -= log_trans(2,3);
911  // kai_loc_sub(3) += log_trans(1,2); kai_loc_sub(4) -= log_trans(0,2);
912  // kai_loc_sub(5) += log_trans(0,1);
913 
914  // Transform that local representation to the "eigenvector" basis
915  Matrix<float, 6, 1> kai_b_old;
916  kai_b_old = Bii.colPivHouseholderQr().solve(kai_loc_sub);
917 
918  // Filter velocity
919  //--------------------------------------------------------------------------------
920  const float cf = previous_speed_eig_weight * expf(-int(level)),
921  df = previous_speed_const_weight * expf(-int(level));
922  Matrix<float, 6, 1> kai_b_fil;
923  for (unsigned int i = 0; i < 6; i++)
924  kai_b_fil(i) =
925  (kai_b(i) +
926  (cf * eigensolver.eigenvalues()(i, 0) + df) * kai_b_old(i)) /
927  (1.f + cf * eigensolver.eigenvalues()(i) + df);
928 
929  // Transform filtered velocity to the local reference frame
930  Matrix<float, 6, 1> kai_loc_fil =
931  Bii.inverse().colPivHouseholderQr().solve(kai_b_fil);
932 
933  // Compute the rigid transformation
934  mrpt::math::CArrayDouble<6> aux_vel(kai_loc_fil.cast<double>() / fps);
935  poses::CPose3D aux1, aux2;
936  CMatrixDouble44 trans;
937  aux2 = aux1.exp(aux_vel);
938  aux2.getHomogeneousMatrix(trans);
939  transformations[level] = trans.cast<float>();
940 }
941 
943 {
944  // First, compute the overall transformation
945  //---------------------------------------------------
946  Matrix4f acu_trans;
947  acu_trans.setIdentity();
948  for (unsigned int i = 1; i <= ctf_levels; i++)
949  acu_trans = transformations[i - 1] * acu_trans;
950 
951  // Compute the new estimates in the local and absolutes reference frames
952  //---------------------------------------------------------------------
953  CMatrixDouble44 mat_aux = acu_trans.cast<double>();
954  poses::CPose3D aux(mat_aux);
955  CArrayDouble<6> kai_level_acu(aux.ln() * fps);
956  kai_loc = kai_level_acu.cast<float>();
957 
958  //---------------------------------------------------------------------------------------------
959  // Directly from Eigen:
960  //- Eigen 3.1.0 needed for Matrix::log()
961  //- The line "#include <unsupported/Eigen/MatrixFunctions>" should be
962  // uncommented (CDifodo.h)
963  //
964  // Matrix<float, 4, 4> log_trans = fps*acu_trans.log();
965  // kai_loc(0) = log_trans(0,3); kai_loc(1) = log_trans(1,3); kai_loc(2) =
966  // log_trans(2,3);
967  // kai_loc(3) = -log_trans(1,2); kai_loc(4) = log_trans(0,2); kai_loc(5) =
968  // -log_trans(0,1);
969  //---------------------------------------------------------------------------------------------
970 
971  CMatrixDouble33 inv_trans;
972  CMatrixFloat31 v_abs, w_abs;
973 
974  cam_pose.getRotationMatrix(inv_trans);
975  v_abs = inv_trans.cast<float>() * kai_loc.topRows(3);
976  w_abs = inv_trans.cast<float>() * kai_loc.bottomRows(3);
977  kai_abs.topRows<3>() = v_abs;
978  kai_abs.bottomRows<3>() = w_abs;
979 
980  // Update poses
981  //-------------------------------------------------------
982  cam_oldpose = cam_pose;
983  CMatrixDouble44 aux_acu = acu_trans;
984  poses::CPose3D pose_aux(aux_acu);
985  cam_pose = cam_pose + pose_aux;
986 
987  // Compute the velocity estimate in the new ref frame (to be used by the
988  // filter in the next iteration)
989  //---------------------------------------------------------------------------------------------------
990  cam_pose.getRotationMatrix(inv_trans);
991  kai_loc_old.topRows<3>() =
992  inv_trans.inverse().cast<float>() * kai_abs.topRows(3);
993  kai_loc_old.bottomRows<3>() =
994  inv_trans.inverse().cast<float>() * kai_abs.bottomRows(3);
995 }
996 
997 void CDifodo::setFOV(float new_fovh, float new_fovv)
998 {
999  fovh = M_PI * new_fovh / 180.0;
1000  fovv = M_PI * new_fovv / 180.0;
1001 }
1002 
1003 void CDifodo::getPointsCoord(MatrixXf& x, MatrixXf& y, MatrixXf& z)
1004 {
1005  x.resize(rows, cols);
1006  y.resize(rows, cols);
1007  z.resize(rows, cols);
1008 
1009  z = depth_inter[0];
1010  x = xx_inter[0];
1011  y = yy_inter[0];
1012 }
1013 
1015  MatrixXf& cur_du, MatrixXf& cur_dv, MatrixXf& cur_dt)
1016 {
1017  cur_du.resize(rows, cols);
1018  cur_dv.resize(rows, cols);
1019  cur_dt.resize(rows, cols);
1020 
1021  cur_du = du;
1022  cur_dv = dv;
1023  cur_dt = dt;
1024 }
1025 
1026 void CDifodo::getWeights(MatrixXf& w)
1027 {
1028  w.resize(rows, cols);
1029  w = weights;
1030 }
GLdouble GLdouble u2
Definition: glext.h:5566
double Tac() noexcept
Stops the stopwatch.
Definition: CTicTac.cpp:90
const GLbyte * weights
Definition: glext.h:4450
GLdouble GLdouble z
Definition: glext.h:3872
GLuint GLenum matrix
Definition: glext.h:6975
void buildCoordinatesPyramid()
Create the gaussian image pyramid according to the number of coarse-to-fine levels.
Definition: CDifodo.cpp:110
void calculateDepthDerivatives()
Calculates the depth derivatives respect to u,v (rows and cols) and t (time)
Definition: CDifodo.cpp:538
A high-performance stopwatch, with typical resolution of nanoseconds.
CArrayNumeric is an array for numeric types supporting several mathematical operations (actually...
Definition: CArrayNumeric.h:25
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glext.h:3600
STL namespace.
GLdouble s
Definition: glext.h:3676
GLenum GLsizei width
Definition: glext.h:3531
void computeWeights()
This method computes the weighting fuction associated to measurement and linearization errors...
Definition: CDifodo.cpp:618
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:4178
void solveOneLevel()
The Solver.
Definition: CDifodo.cpp:756
T square(const T x)
Inline function for the square of a number.
void setFOV(float new_fovh, float new_fovv)
Set the horizontal and vertical field of vision (in degrees)
Definition: CDifodo.cpp:997
void odometryCalculation()
This method performs all the necessary steps to estimate the camera velocity once the new image is re...
Definition: CDifodo.cpp:814
void calculateCoord()
Calculate the "average" coordinates of the points observed by the camera between two consecutive fram...
Definition: CDifodo.cpp:503
A numeric matrix of compile-time fixed size.
This base provides a set of functions for maths stuff.
void getDepthDerivatives(Eigen::MatrixXf &cur_du, Eigen::MatrixXf &cur_dv, Eigen::MatrixXf &cur_dt)
Get the depth derivatives (last level) respect to u,v and t respectively.
Definition: CDifodo.cpp:1014
void getWeights(Eigen::MatrixXf &we)
Get the matrix of weights.
Definition: CDifodo.cpp:1026
CONTAINER::Scalar sum(const CONTAINER &v)
Computes the sum of all the elements.
#define M_PIf
Definition: common.h:61
Classes for computer vision, detectors, features, etc.
Definition: CCamModel.h:18
void filterLevelSolution()
Method to filter the velocity at each level of the pyramid.
Definition: CDifodo.cpp:872
void poseUpdate()
Update camera pose and the velocities for the filter.
Definition: CDifodo.cpp:942
void getPointsCoord(Eigen::MatrixXf &x, Eigen::MatrixXf &y, Eigen::MatrixXf &z)
Get the coordinates of the points considered by the visual odometry method.
Definition: CDifodo.cpp:1003
const GLdouble * v
Definition: glext.h:3678
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:86
GLint level
Definition: glext.h:3600
GLenum GLint GLint y
Definition: glext.h:3538
GLfloat GLfloat GLfloat v2
Definition: glext.h:4107
GLuint res
Definition: glext.h:7268
GLenum GLint x
Definition: glext.h:3538
void Tic() noexcept
Starts the stopwatch.
Definition: CTicTac.cpp:79
void getRotationMatrix(mrpt::math::CMatrixDouble33 &ROT) const
Get the 3x3 rotation matrix.
Definition: CPose3D.h:230
GLenum GLsizei GLsizei height
Definition: glext.h:3554
static CPose3D exp(const mrpt::math::CArrayNumeric< double, 6 > &vect, bool pseudo_exponential=false)
Exponentiate a Vector in the SE(3) Lie Algebra to generate a new CPose3D (static method).
Definition: CPose3D.cpp:758
void buildCoordinatesPyramidFast()
Definition: CDifodo.cpp:269
void getHomogeneousMatrix(mrpt::math::CMatrixDouble44 &out_HM) const
Returns the corresponding 4x4 homogeneous transformation matrix for the point(translation) or pose (t...
Definition: CPose3D.h:221
void performWarping()
Warp the second depth image against the first one according to the 3D transformations accumulated up ...
Definition: CDifodo.cpp:386
int round(const T value)
Returns the closer integer (int) to x.
Definition: round.h:23



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020