optimizer.cpp
Go to the documentation of this file.
1 
4 #include "optimizer.h"
5 #include <librealsense2/rsutil.h>
6 #include <algorithm>
7 #include <array>
8 #include "coeffs.h"
9 #include "cost.h"
10 #include "uvmap.h"
11 #include "k-to-dsm.h"
12 #include "debug.h"
13 #include "utils.h"
14 
16 
17 
18 namespace
19 {
20  std::vector<double> calc_intensity( std::vector<double> const & image1, std::vector<double> const & image2 )
21  {
22  std::vector<double> res( image1.size(), 0 );
23 
24  for(size_t i = 0; i < image1.size(); i++ )
25  {
26  res[i] = sqrt( pow( image1[i], 2 ) + pow( image2[i], 2 ) );
27  }
28  return res;
29  }
30 
31  template<class T>
32  double dot_product( std::vector<T> const & sub_image, std::vector<double> const & mask )
33  {
34  double res = 0;
35 
36  for( auto i = 0; i < sub_image.size(); i++ )
37  {
38  res += sub_image[i] * mask[i];
39  }
40 
41  return res;
42  }
43 
44  template<class T>
45  std::vector<double> convolution(std::vector<T> const& image,
46  size_t image_width, size_t image_height,
47  size_t mask_width, size_t mask_height,
48  std::function< double(std::vector<T> const& sub_image) > convolution_operation
49  )
50  {
51  std::vector<double> res(image.size(), 0);
52 
53  for (size_t i = 0; i < image_height - mask_height + 1; i++)
54  {
55  for (size_t j = 0; j < image_width - mask_width + 1; j++)
56  {
57  std::vector<T> sub_image(mask_width * mask_height, 0);
58  auto ind = 0;
59  for (size_t l = 0; l < mask_height; l++)
60  {
61  for (size_t k = 0; k < mask_width; k++)
62  {
63  size_t p = (i + l) * image_width + j + k;
64  sub_image[ind++] = (image[p]);
65  }
66 
67  }
68  auto mid = (i + mask_height / 2) * image_width + j + mask_width / 2;
69  res[mid] = convolution_operation(sub_image);
70  }
71  }
72  return res;
73  }
74 
75  template<class T>
76  std::vector<double> calc_horizontal_gradient( std::vector<T> const & image, size_t image_width, size_t image_height )
77  {
78  std::vector<double> horizontal_gradients = { -1, -2, -1,
79  0, 0, 0,
80  1, 2, 1 };
81 
82  return convolution<T>( image, image_width, image_height, 3, 3, [&]( std::vector<T> const & sub_image )
83  {return dot_product( sub_image, horizontal_gradients ) / (double)8; } );
84  }
85 
86  template<class T>
87  std::vector<double> calc_vertical_gradient( std::vector<T> const & image, size_t image_width, size_t image_height )
88  {
89  std::vector<double> vertical_gradients = { -1, 0, 1,
90  -2, 0, 2,
91  -1, 0, 1 };
92 
93  return convolution<T>( image, image_width, image_height, 3, 3, [&]( std::vector<T> const & sub_image )
94  {return dot_product( sub_image, vertical_gradients ) / (double)8; } );;
95  }
96 
97  template<class T>
98  std::vector<double> calc_edges( std::vector<T> const & image, size_t image_width, size_t image_height )
99  {
100  auto vertical_edge = calc_vertical_gradient( image, image_width, image_height );
101 
102  auto horizontal_edge = calc_horizontal_gradient( image, image_width, image_height );
103 
104  auto edges = calc_intensity( vertical_edge, horizontal_edge );
105 
106  return edges;
107  }
108 
109  std::pair<int, int> const dir_map[direction::deg_none] =
110  {
111  { 1, 0}, // dir_0
112  { 1, 1}, // dir_45
113  { 0, 1}, // deg_90
114  {-1, 1} // deg_135
115  };
116 
117 }
118 
119 
121 {
122  return librealsense::to_string()
123  << '[' << ( is_manual_trigger ? "MANUAL" : "AUTO" ) << ' ' << hum_temp << "degC"
124  << " digital gain="
125  << (digital_gain == RS2_DIGITAL_GAIN_HIGH ? "high/long"
126  : digital_gain == RS2_DIGITAL_GAIN_LOW ? "low/short"
127  : "??" )
128  << " receiver gain=" << receiver_gain << ']';
129 }
130 
131 
132 optimizer::optimizer( settings const & s, bool debug_mode )
133  : _settings( s )
134  , _debug_mode( debug_mode )
135 {
136  AC_LOG( DEBUG, "Optimizer settings are " << _settings.to_string() );
139  else
141 }
142 
143 static std::vector< double > get_direction_deg(
144  std::vector<double> const & gradient_x,
145  std::vector<double> const & gradient_y
146 )
147 {
148  std::vector<double> res( gradient_x.size(), deg_none );
149 
150  for(size_t i = 0; i < gradient_x.size(); i++ )
151  {
152  int closest = -1;
153  auto angle = atan2( gradient_y[i], gradient_x[i] )* 180.f / M_PI;
154  angle = angle < 0 ? 180 + angle : angle;
155  auto dir = fmod( angle, 180 );
156 
157 
158  res[i] = dir;
159  }
160  return res;
161 }
162 static std::vector< double > get_direction_deg2(
163  std::vector<double> const& gradient_x,
164  std::vector<double> const& gradient_y
165  )
166 {
167  std::vector<double> res(gradient_x.size(), deg_none);
168 
169  for (size_t i = 0; i < gradient_x.size(); i++)
170  {
171  int closest = -1;
172  auto angle = atan2(gradient_y[i], gradient_x[i])*180.f / M_PI;
173  angle = angle < 0 ? 360+angle : angle;
174  auto dir = fmod(angle, 360);
175 
176 
177  res[i] = dir;
178  }
179  return res;
180 }
181 static
182 std::pair< int, int > get_prev_index(
183  direction dir,
184  int i, int j,
185  size_t width, size_t height )
186 {
187  int edge_minus_idx = 0;
188  int edge_minus_idy = 0;
189 
190  auto & d = dir_map[dir];
191  if( j < d.first )
192  edge_minus_idx = int(width) - 1 - j;
193  else if( j - d.first >= width )
194  edge_minus_idx = 0;
195  else
196  edge_minus_idx = j - d.first;
197 
198  if( i - d.second < 0 )
199  edge_minus_idy = int(height) - 1 - i;
200  else if( i - d.second >= height )
201  edge_minus_idy = 0;
202  else
203  edge_minus_idy = i - d.second;
204 
205  return { edge_minus_idx, edge_minus_idy };
206 }
207 
208 static
209 std::pair< int, int > get_next_index(
210  direction dir,
211  int i, int j,
212  size_t width, size_t height
213 )
214 {
215  auto & d = dir_map[dir];
216 
217  int edge_plus_idx = 0;
218  int edge_plus_idy = 0;
219 
220  if( j + d.first < 0 )
221  edge_plus_idx = int(width) - 1 - j;
222  else if( j + d.first >= width )
223  edge_plus_idx = 0;
224  else
225  edge_plus_idx = j + d.first;
226 
227  if( i + d.second < 0 )
228  edge_plus_idy = int(height) - 1 - i;
229  else if( i + d.second >= height )
230  edge_plus_idy = 0;
231  else
232  edge_plus_idy = i + d.second;
233 
234  return { edge_plus_idx, edge_plus_idy };
235 }
236 
237 void zero_margin( std::vector< double > & gradient, size_t margin, size_t width, size_t height )
238 {
239  auto it = gradient.begin();
240  for(size_t m = 0; m < margin; ++m )
241  {
242  for(size_t i = 0; i < width; i++ )
243  {
244  // zero mask of 2nd row, and row before the last
245  *( it + m * width + i ) = 0;
246  *( it + width * ( height - m - 1 ) + i ) = 0;
247  }
248  for(size_t i = 0; i < height; i++ )
249  {
250  // zero mask of 2nd column, and column before the last
251  *( it + i * width + m ) = 0;
252  *( it + i * width + ( width - m - 1 ) ) = 0;
253  }
254  }
255 }
256 
257 template < class T >
258 void sample_by_mask( std::vector< T > & filtered,
259  std::vector< T > const & origin,
260  std::vector< byte > const & valid_edge_by_ir,
261  size_t const width,
262  size_t const height )
263 {
264  //%function [values] = sampleByMask(I,binMask)
265  //% % Extract values from image I using the binMask with the order being
266  //% % row and then column
267  //% I = I';
268  //% values = I(binMask');
269  //end
270  for(size_t x = 0; x < origin.size(); ++x )
271  if( valid_edge_by_ir[x] )
272  filtered.push_back( origin[x] );
273 }
274 
275 template < class T >
276 void depth_filter( std::vector< T > & filtered,
277  std::vector< T > const & origin,
278  std::vector< byte > const & valid_edge_by_ir,
279  size_t const width,
280  size_t const height )
281 {
282  // origin and valid_edge_by_ir are of same size
283  for(size_t j = 0; j < width; j++ )
284  {
285  for(size_t i = 0; i < height; i++ )
286  {
287  auto idx = i * width + j;
288  if( valid_edge_by_ir[idx] )
289  {
290  filtered.push_back( origin[idx] );
291  }
292  }
293  }
294 }
295 
296 void grid_xy(
297  std::vector<double>& gridx,
298  std::vector<double>& gridy,
299  size_t width,
300  size_t height)
301 {
302  for (size_t i = 1; i <= height; i++)
303  {
304  for (size_t j = 1; j <= width; j++)
305  {
306  gridx.push_back( double( j ) );
307  gridy.push_back( double( i ) );
308  }
309  }
310 }
311 
312 template<class T>
313 std::vector< double > interpolation( std::vector< T > const & grid_points,
314  std::vector< double > const x[],
315  std::vector< double > const y[],
316  size_t dim,
317  size_t valid_size,
318  size_t valid_width )
319 {
320  std::vector<double> local_interp;
321  local_interp.reserve( valid_size * dim );
322  auto iedge_it = grid_points.begin();
323  std::vector<double>::const_iterator loc_reg_x[4];
324  std::vector<double>::const_iterator loc_reg_y[4];
325  for( auto i = 0; i < dim; i++ )
326  {
327  loc_reg_x[i] = x[i].begin();
328  loc_reg_y[i] = y[i].begin();
329  }
330  for (size_t i = 0; i < valid_size; i++)
331  {
332  for (size_t k = 0; k < dim; k++)
333  {
334  auto idx = *(loc_reg_x[k] + i) - 1;
335  auto idy = *(loc_reg_y[k] + i) - 1;
336  //assert(_ir.width * idy + idx <= _ir.width * _ir.height);
337  auto val = *( iedge_it + size_t( valid_width * idy + idx ) ); // find value in iEdge
338  local_interp.push_back(val);
339  }
340  }
341  return local_interp;
342 }
343 std::vector<uint8_t> is_suppressed(std::vector<double> const & local_edges, size_t valid_size)
344 {
345  std::vector<uint8_t> is_supressed;
346  auto loc_edg_it = local_edges.begin();
347  for (size_t i = 0; i < valid_size; i++)
348  {
349  //isSupressed = localEdges(:,3) >= localEdges(:,2) & localEdges(:,3) >= localEdges(:,4);
350  auto vec2 = *(loc_edg_it + 1);
351  auto vec3 = *(loc_edg_it + 2);
352  auto vec4 = *(loc_edg_it + 3);
353  loc_edg_it += 4;
354  bool res = (vec3 >= vec2) && (vec3 >= vec4);
355  is_supressed.push_back(res);
356  }
357  return is_supressed;
358 }
359 
360 static std::vector< double > depth_mean( std::vector< double > const & local_x,
361  std::vector< double > const & local_y )
362 {
363  std::vector<double> res;
364  res.reserve( local_x.size() );
365  size_t size = local_x.size() / 2;
366  auto itx = local_x.begin();
367  auto ity = local_y.begin();
368  for (size_t i = 0; i < size; i++, ity += 2, itx += 2)
369  {
370  double valy = (*ity + *(ity + 1)) / 2;
371  double valx = (*itx + *(itx + 1)) / 2;
372  res.push_back(valy);
373  res.push_back(valx);
374  }
375 
376  return res;
377 }
378 
379 static std::vector< double > sum_gradient_depth( std::vector< double > const & gradient,
380  std::vector< double > const & direction_per_pixel )
381 {
382  std::vector<double> res;
383  size_t size = direction_per_pixel.size() / 2;
384  res.reserve( size );
385  auto it_dir = direction_per_pixel.begin();
386  auto it_grad = gradient.begin();
387  for (size_t i = 0; i < size; i++, it_dir+=2, it_grad+=2)
388  {
389  // normalize : res = val/sqrt(row_sum)
390  auto rorm_dir1 = *it_dir / sqrt(abs(*it_dir) + abs(*(it_dir + 1)));
391  auto rorm_dir2 = *(it_dir+1) / sqrt(abs(*it_dir) + abs(*(it_dir + 1)));
392  auto val = abs(*it_grad * rorm_dir1 + *(it_grad + 1) * rorm_dir2);
393  res.push_back(val);
394  }
395  return res;
396 }
397 
398 
399 std::vector< byte > find_valid_depth_edges( std::vector< double > const & grad_in_direction,
400  std::vector< byte > const & is_supressed,
401  std::vector< double > const & values_for_subedges,
402  std::vector< double > const & ir_local_edges,
403  const params & p )
404 {
405  std::vector< byte > res;
406  res.reserve( grad_in_direction.size() );
407  //%validEdgePixels = zGradInDirection > params.gradZTh & isSupressed & zValuesForSubEdges > 0;
409  {
410  for (size_t i = 0; i < grad_in_direction.size(); i++)
411  {
412  bool cond1 = (grad_in_direction[i] > p.grad_z_low_th && ir_local_edges[i * 4 + 2] > p.grad_ir_high_th) ||
413  (grad_in_direction[i] > p.grad_z_high_th && ir_local_edges[i * 4 + 2] > p.grad_ir_low_th);
414 
415  bool cond2 = is_supressed[i];
416  bool cond3 = values_for_subedges[i] > 0;
417  res.push_back(cond1 && cond2 && cond3);
418  }
419  }
420  else
421  {
422  for (size_t i = 0; i < grad_in_direction.size(); i++)
423  {
424  bool cond1 = grad_in_direction[i] > p.grad_z_threshold;
425  bool cond2 = is_supressed[i];
426  bool cond3 = values_for_subedges[i] > 0;
427  res.push_back(cond1 && cond2 && cond3);
428  }
429  }
430 
431  return res;
432 }
433 
434 
435 static std::vector< double > find_local_values_min( std::vector< double > const & local_values )
436 {
437  std::vector<double> res;
438  size_t size = local_values.size() / 4;
439  res.reserve( size );
440  auto it = local_values.begin();
441  for (size_t i = 0; i < size; i++)
442  {
443  auto val1 = *it;
444  auto val2 = *(it + 1);
445  auto val3 = *(it + 2);
446  auto val4 = *(it + 3);
447  it += 4;
448  double res_val = std::min(val1, std::min(val2, std::min(val3, val4)));
449  res.push_back(res_val);
450  }
451  return res;
452 }
453 
454 
455 void optimizer::set_z_data( std::vector< z_t > && depth_data,
457  rs2_dsm_params const & dsm_params,
458  algo_calibration_info const & cal_info,
459  algo_calibration_registers const & cal_regs, float depth_units )
460 {
461  _original_dsm_params = dsm_params;
462  _k_to_DSM = std::make_shared<k_to_DSM>(dsm_params, cal_info, cal_regs, _params.max_scaling_step);
463 
464  /*[zEdge,Zx,Zy] = OnlineCalibration.aux.edgeSobelXY(uint16(frame.z),2); % Added the second input - margin to zero out
465  [iEdge,Ix,Iy] = OnlineCalibration.aux.edgeSobelXY(uint16(frame.i),2); % Added the second input - margin to zero out
466  validEdgePixelsByIR = iEdge>params.gradITh; */
467  _params.set_depth_resolution(depth_intrinsics.width, depth_intrinsics.height, _settings.digital_gain);
468  _z.width = depth_intrinsics.width;
469  _z.height = depth_intrinsics.height;
471  _z.orig_dsm_params = dsm_params;
473 
474  _z.frame = std::move(depth_data);
475 
476  auto z_gradient_x = calc_vertical_gradient(_z.frame, depth_intrinsics.width, depth_intrinsics.height);
477  auto z_gradient_y = calc_horizontal_gradient( _z.frame, depth_intrinsics.width, depth_intrinsics.height );
478  auto ir_gradient_x = calc_vertical_gradient( _ir.ir_frame, depth_intrinsics.width, depth_intrinsics.height );
479  auto ir_gradient_y = calc_horizontal_gradient( _ir.ir_frame, depth_intrinsics.width, depth_intrinsics.height );
480 
481  // set margin of 2 pixels to 0
482  zero_margin( z_gradient_x, 2, _z.width, _z.height );
483  zero_margin( z_gradient_y, 2, _z.width, _z.height );
484  zero_margin( ir_gradient_x, 2, _z.width, _z.height );
485  zero_margin( ir_gradient_y, 2, _z.width, _z.height );
486 
487  auto ir_edges = calc_intensity( ir_gradient_x, ir_gradient_y );
488  std::vector< byte > valid_edge_pixels_by_ir;
489  {
490  auto z_edges = calc_intensity( z_gradient_x, z_gradient_y );
491  valid_edge_pixels_by_ir.reserve( ir_edges.size() );
492 
493  for( auto ir = ir_edges.begin(), z = z_edges.begin();
494  ir < ir_edges.end() && z < z_edges.end();
495  ir++, z++ )
496  {
497  bool valid_edge;
499  {
500  valid_edge = ( *ir > _params.grad_ir_high_th && *z > _params.grad_z_low_th )
501  || ( *ir > _params.grad_ir_low_th && *z > _params.grad_z_high_th );
502  }
503  else
504  {
505  valid_edge = ( *ir > _params.grad_ir_threshold );
506  }
507  valid_edge_pixels_by_ir.push_back( valid_edge );
508  }
509 
510  if( _debug_mode )
511  _z.edges = std::move( z_edges );
512  }
513 
514 
515  /*sz = size(frame.i);
516  [gridX,gridY] = meshgrid(1:sz(2),1:sz(1)); % gridX/Y contains the indices of the pixels
517  sectionMapDepth = OnlineCalibration.aux.sectionPerPixel(params);
518  */
519  // Get a map for each pixel to its corresponding section
520  std::vector< byte > section_map_depth;
521  section_map_depth.resize(_z.width * _z.height);
522  size_t const section_w = _params.num_of_sections_for_edge_distribution_x; //% params.numSectionsH
523  size_t const section_h = _params.num_of_sections_for_edge_distribution_y; //% params.numSectionsH
524  section_per_pixel(_z, section_w, section_h, section_map_depth.data());
525 
526  //%locRC = [sampleByMask( gridY, validEdgePixelsByIR ), sampleByMask( gridX, validEdgePixelsByIR )];
527  //%sectionMapValid = sampleByMask( sectionMapDepth, validEdgePixelsByIR );
528  //%IxValid = sampleByMask( Ix, validEdgePixelsByIR );
529  //%IyValid = sampleByMask( Iy, validEdgePixelsByIR );
530 
531  std::vector< double > valid_location_rc_x;
532  std::vector< double > valid_location_rc_y;
533  {
534  std::vector< double > grid_x, grid_y;
535  grid_xy( grid_x, grid_y, _z.width, _z.height );
536  sample_by_mask( valid_location_rc_x, grid_x, valid_edge_pixels_by_ir, _z.width, _z.height );
537  sample_by_mask( valid_location_rc_y, grid_y, valid_edge_pixels_by_ir, _z.width, _z.height );
538  }
539  std::vector< byte > valid_section_map;
540  std::vector< double > valid_gradient_x;
541  std::vector< double > valid_gradient_y;
542 
543  sample_by_mask( valid_section_map, section_map_depth, valid_edge_pixels_by_ir, _z.width, _z.height );
544  sample_by_mask( valid_gradient_x, ir_gradient_x, valid_edge_pixels_by_ir, _z.width, _z.height );
545  sample_by_mask( valid_gradient_y, ir_gradient_y, valid_edge_pixels_by_ir, _z.width, _z.height );
546 
547  auto itx = valid_location_rc_x.begin();
548  auto ity = valid_location_rc_y.begin();
549 
550  std::vector< double > valid_location_rc;
551  for (size_t i = 0; i < valid_location_rc_x.size(); i++)
552  {
553  auto x = *(itx + i);
554  auto y = *(ity + i);
555  valid_location_rc.push_back(y);
556  valid_location_rc.push_back(x);
557  }
558 
559  /*
560  directionInDeg = atan2d(IyValid,IxValid);
561  directionInDeg(directionInDeg<0) = directionInDeg(directionInDeg<0) + 360;
562  [~,directionIndex] = min(abs(directionInDeg - [0:45:315]),[],2); % Quantize the direction to 4 directions (don't care about the sign)
563  */
564 
565  if( _debug_mode )
566  _ir.direction_deg = get_direction_deg2( valid_gradient_x, valid_gradient_y );
567 
568  std::vector< direction > dirs = get_direction2( valid_gradient_x, valid_gradient_y );
569 
570  /*dirsVec = [0,1; 1,1; 1,0; 1,-1]; % These are the 4 directions
571  dirsVec = [dirsVec;-dirsVec];
572  if 1
573  % Take the right direction
574  dirPerPixel = dirsVec(directionIndex,:);
575  localRegion = locRC + dirPerPixel.*reshape(vec(-2:1),1,1,[]);
576  localEdges = squeeze(interp2(iEdge,localRegion(:,2,:),localRegion(:,1,:)));
577  isSupressed = localEdges(:,3) >= localEdges(:,2) & localEdges(:,3) >= localEdges(:,4);
578 
579  fraqStep = (-0.5*(localEdges(:,4)-localEdges(:,2))./(localEdges(:,4)+localEdges(:,2)-2*localEdges(:,3))); % The step we need to move to reach the subpixel gradient i nthe gradient direction
580  fraqStep((localEdges(:,4)+localEdges(:,2)-2*localEdges(:,3))==0) = 0;
581 
582  locRCsub = locRC + fraqStep.*dirPerPixel;*/
583  double directions[8][2] = { {0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1} };
584 
585  std::vector< double > direction_per_pixel;
586  std::vector< double > direction_per_pixel_x; //used later when finding valid direction per pixel
587 
588  for(size_t i = 0; i < dirs.size(); i++ )
589  {
590  int idx = dirs[i];
591  direction_per_pixel.push_back(directions[idx][0]);
592  direction_per_pixel.push_back(directions[idx][1]);
593  direction_per_pixel_x.push_back(directions[idx][0]);
594  }
595  double vec[4] = { -2,-1,0,1 }; // one pixel along gradient direction, 2 pixels against gradient direction
596 
597  auto loc_it = valid_location_rc.begin();
598  auto dir_pp_it = direction_per_pixel.begin();
599 
600  std::vector< double > local_region[4];
601  for( auto k = 0; k < 4; k++ )
602  {
603  local_region[k].reserve( direction_per_pixel.size() );
604  for(size_t i = 0; i < direction_per_pixel.size(); i++ )
605  {
606  double val = *( loc_it + i ) + *( dir_pp_it + i ) * vec[k];
607  local_region[k].push_back( val );
608  }
609  }
610  std::vector< double > local_region_x[4];
611  std::vector< double > local_region_y[4];
612  for( auto k = 0; k < 4; k++ )
613  {
614  local_region_x[k].reserve( 2 * valid_location_rc_x.size() );
615  local_region_y[k].reserve( 2 * valid_location_rc_x.size() );
616  for(size_t i = 0; i < 2 * valid_location_rc_x.size(); i++ )
617  {
618  local_region_y[k].push_back( *( local_region[k].begin() + i ) );
619  i++;
620  local_region_x[k].push_back( *( local_region[k].begin() + i ) );
621  }
622  }
623  // interpolation
624  _ir.local_edges = interpolation(ir_edges,local_region_x, local_region_y, 4, valid_location_rc_x.size(), _ir.width);
625 
626  // is suppressed
627  _ir.is_supressed = is_suppressed(_ir.local_edges, valid_location_rc_x.size());
628 
629 
630  /*fraqStep = (-0.5*(localEdges(:,4)-localEdges(:,2))./(localEdges(:,4)+localEdges(:,2)-2*localEdges(:,3))); % The step we need to move to reach the subpixel gradient i nthe gradient direction
631  fraqStep((localEdges(:,4)+localEdges(:,2)-2*localEdges(:,3))==0) = 0;
632 
633  locRCsub = locRC + fraqStep.*dirPerPixel;
634 
635  % Calculate the Z gradient for thresholding
636  localZx = squeeze(interp2(Zx,localRegion(:,2,2:3),localRegion(:,1,2:3)));
637  localZy = squeeze(interp2(Zy,localRegion(:,2,2:3),localRegion(:,1,2:3)));
638  zGrad = [mean(localZy,2) ,mean(localZx,2)];
639  zGradInDirection = abs(sum(zGrad.*normr(dirPerPixel),2));
640  % Take the z value of the closest part of the edge
641  localZvalues = squeeze(interp2(frame.z,localRegion(:,2,:),localRegion(:,1,:)));
642 
643  zValuesForSubEdges = min(localZvalues,[],2);
644  edgeSubPixel = fliplr(locRCsub);% From Row-Col to XY*/
645 
646  std::vector< double > ::iterator loc_edg_it = _ir.local_edges.begin();
647  auto valid_loc_rc = valid_location_rc.begin(); // locRC
648  auto dir_per_pixel_it = direction_per_pixel.begin(); // dirPerPixel
649 
650  std::vector< double > edge_sub_pixel_x;
651  std::vector< double > edge_sub_pixel_y;
652  std::vector< double > fraq_step; // debug only
653  std::vector< double > local_rc_subpixel; // debug only
654  std::vector< double > edge_sub_pixel; // debug only
655 
656  for(size_t i = 0; i < valid_location_rc_x.size(); i++ )
657  {
658  double vec2 = *(loc_edg_it + 1);
659  double vec3 = *(loc_edg_it + 2);
660  double vec4 = *(loc_edg_it + 3);
661  loc_edg_it += 4;
662 
663  // The step we need to move to reach the subpixel gradient in the gradient direction
664  //%fraqStep = (-0.5*(localEdges(:,4) - localEdges(:,2)). / (localEdges(:,4) + localEdges(:,2) - 2 * localEdges(:,3)));
665  //%fraqStep( (localEdges(:,4) + localEdges(:,2) - 2 * localEdges(:,3)) == 0 ) = 0;
666  double const denom = vec4 + vec2 - 2 * vec3;
667  double const res = ( denom == 0 ) ? 0 : ( -0.5 * ( vec4 - vec2 ) / denom );
668 
669  auto valx = *valid_loc_rc + *dir_per_pixel_it * res;
670  valid_loc_rc++;
671  dir_per_pixel_it++;
672  auto valy = *valid_loc_rc + *dir_per_pixel_it * res;
673  valid_loc_rc++;
674  dir_per_pixel_it++;
675 
676  if( _debug_mode )
677  {
678  fraq_step.push_back( res );
679  local_rc_subpixel.push_back( valx );
680  local_rc_subpixel.push_back( valy );
681  edge_sub_pixel.push_back( valy );
682  edge_sub_pixel.push_back( valx );
683  }
684  edge_sub_pixel_x.push_back(valy);
685  edge_sub_pixel_y.push_back(valx);
686  }
687  _z.edge_sub_pixel = std::move( edge_sub_pixel );
688  _z.local_rc_subpixel = std::move( local_rc_subpixel );
689  _ir.fraq_step = std::move( fraq_step );
690 
691  std::vector< double > grad_in_direction;
692  {
693  std::vector< double > local_x;
694  std::vector< double > local_y;
695  std::vector< double > gradient;
696 
697  local_x = interpolation( z_gradient_x,
698  local_region_x + 1,
699  local_region_y + 1,
700  2,
701  valid_location_rc_x.size(),
702  _z.width );
703  local_y = interpolation( z_gradient_y,
704  local_region_x + 1,
705  local_region_y + 1,
706  2,
707  valid_location_rc_x.size(),
708  _z.width );
709  gradient = depth_mean( local_x, local_y );
710  grad_in_direction = sum_gradient_depth( gradient, direction_per_pixel );
711  if( _debug_mode )
712  {
713  _z.local_x = std::move( local_x );
714  _z.local_y = std::move( local_y );
715  _z.gradient = std::move( gradient );
716  }
717  }
718  std::vector< double > values_for_subedges;
719  {
720  std::vector< double > local_values = interpolation( _z.frame,
721  local_region_x,
722  local_region_y,
723  4,
724  valid_location_rc_x.size(),
725  _z.width );
726  values_for_subedges = find_local_values_min( local_values );
727  if( _debug_mode )
728  _z.local_values = std::move( local_values );
729  }
730 
731  //_params.alpha;
732  /* validEdgePixels = zGradInDirection > params.gradZTh & isSupressed & zValuesForSubEdges > 0;
733 
734  zGradInDirection = zGradInDirection(validEdgePixels);
735  edgeSubPixel = edgeSubPixel(validEdgePixels,:);
736  zValuesForSubEdges = zValuesForSubEdges(validEdgePixels);
737  dirPerPixel = dirPerPixel(validEdgePixels);
738  sectionMapDepth = sectionMapValid(validEdgePixels);
739  directionIndex = directionIndex(validEdgePixels);
740  directionIndex(directionIndex>4) = directionIndex(directionIndex>4)-4;% Like taking abosoulte value on the direction
741  */
742  _z.supressed_edges = find_valid_depth_edges( grad_in_direction,
744  values_for_subedges,
746  _params);
747 
748  if( _debug_mode )
749  {
751  grad_in_direction,
753  1,
754  _z.supressed_edges.size() );
755  }
756 
757  std::vector< double > valid_edge_sub_pixel_x;
758  std::vector< double > valid_edge_sub_pixel_y;
759  depth_filter( valid_edge_sub_pixel_x,
760  edge_sub_pixel_x,
762  1,
763  _z.supressed_edges.size() );
764  depth_filter( valid_edge_sub_pixel_y,
765  edge_sub_pixel_y,
767  1,
768  _z.supressed_edges.size() );
769 
770  {
771  std::vector< double > valid_values_for_subedges;
772  depth_filter( valid_values_for_subedges, // out
773  values_for_subedges, // in
775  1,
776  _z.supressed_edges.size() );
777  values_for_subedges = valid_values_for_subedges;
778  }
779 
780  /* weights = min(max(zGradInDirection - params.gradZTh,0),params.gradZMax - params.gradZTh);
781  if params.constantWeights
782  weights(:) = params.constantWeightsValue;
783  end
784  xim = edgeSubPixel(:,1)-1;
785  yim = edgeSubPixel(:,2)-1;
786 
787  subPoints = [xim,yim,ones(size(yim))];
788  vertices = subPoints*(pinv(params.Kdepth)').*zValuesForSubEdges/single(params.zMaxSubMM);
789 
790  [uv,~,~] =
791  OnlineCalibration.aux.projectVToRGB(vertices,params.rgbPmat,params.Krgb,params.rgbDistort);
792  isInside = OnlineCalibration.aux.isInsideImage(uv,params.rgbRes);
793 
794  xim = xim(isInside);
795  yim = yim(isInside);
796  zValuesForSubEdges = zValuesForSubEdges(isInside);
797  zGradInDirection = zGradInDirection(isInside);
798  directionIndex = directionIndex(isInside);
799  weights = weights(isInside);
800  vertices = vertices(isInside,:);
801  sectionMapDepth = sectionMapDepth(isInside);*/
803  matrix_3x3 k_depth_pinv = { 0 };
804  pinv_3x3( k.as_3x3().rot, k_depth_pinv.rot );
805  _z.k_depth_pinv = k_depth_pinv;
806 
807  std::vector< byte > is_inside;
808  {
809  std::vector< double3 > vertices_all;
810  {
811  std::vector< double > sub_points;
812  sub_points.reserve( valid_edge_sub_pixel_x.size() * 3 );
813  {
814  std::vector< double > valid_edge_sub_pixel;
815  if( _debug_mode )
816  valid_edge_sub_pixel.reserve( valid_edge_sub_pixel_x.size() );
817  for(size_t i = 0; i < valid_edge_sub_pixel_x.size(); i++ )
818  {
819  if( _debug_mode )
820  {
821  valid_edge_sub_pixel.push_back( *( valid_edge_sub_pixel_x.begin() + i ) );
822  valid_edge_sub_pixel.push_back( *( valid_edge_sub_pixel_y.begin() + i ) );
823  }
824  // subPoints : subPoints = [xim,yim,ones(size(yim))];
825  sub_points.push_back( *( valid_edge_sub_pixel_x.begin() + i ) - 1 );
826  sub_points.push_back( *( valid_edge_sub_pixel_y.begin() + i ) - 1 );
827  sub_points.push_back( 1 );
828  }
829  if( _debug_mode )
830  _z.valid_edge_sub_pixel = std::move( valid_edge_sub_pixel );
831  }
832 
833  vertices_all.reserve( valid_edge_sub_pixel_x.size() );
834  for(size_t i = 0; i < sub_points.size(); i += 3 )
835  {
836  //% vertices = subPoints * pinv(params.Kdepth)' .* zValuesForSubEdges /
837  //params.zMaxSubMM;
838  double sub_points_mult[3];
839  double x = sub_points[i];
840  double y = sub_points[i + 1];
841  double z = sub_points[i + 2];
842  for( auto jj = 0; jj < 3; jj++ )
843  {
844  sub_points_mult[jj] = x * k_depth_pinv.rot[3 * jj + 0]
845  + y * k_depth_pinv.rot[3 * jj + 1]
846  + z * k_depth_pinv.rot[3 * jj + 2];
847  }
848  auto z_value_for_subedge = values_for_subedges[i / 3];
849  auto val1 = sub_points_mult[0] * z_value_for_subedge / _params.max_sub_mm_z;
850  auto val2 = sub_points_mult[1] * z_value_for_subedge / _params.max_sub_mm_z;
851  auto val3 = sub_points_mult[2] * z_value_for_subedge / _params.max_sub_mm_z;
852  vertices_all.push_back( { val1, val2, val3 } );
853  }
854  if( _debug_mode )
855  _z.sub_points = std::move( sub_points );
856  }
857  std::vector< double2 > uvmap = get_texture_map( vertices_all,
860  for(size_t i = 0; i < uvmap.size(); i++ )
861  {
862  //%isInside = xy(:,1) >= 0 & ...
863  //% xy(:,1) <= res(2) - 1 & ...
864  //% xy(:,2) >= 0 & ...
865  //% xy(:,2) <= res(1) - 1;
866  bool cond_x = ( uvmap[i].x >= 0 ) && ( uvmap[i].x <= _yuy.width - 1 );
867  bool cond_y = ( uvmap[i].y >= 0 ) && ( uvmap[i].y <= _yuy.height - 1 );
868  is_inside.push_back( cond_x && cond_y );
869  }
870  depth_filter( _z.vertices, vertices_all, is_inside, 1, is_inside.size() );
871  if( _debug_mode )
872  _z.uvmap = std::move( uvmap );
873  }
874 
875  if( _debug_mode )
877  direction_per_pixel_x,
879  1,
880  _z.supressed_edges.size() );
881 
882  {
883  std::vector< byte > z_valid_section_map;
884  depth_filter( z_valid_section_map,
885  valid_section_map,
887  1,
888  _z.supressed_edges.size() );
889  depth_filter( _z.section_map, z_valid_section_map, is_inside, 1, is_inside.size() );
890  if( _debug_mode )
891  _z.valid_section_map = std::move( z_valid_section_map );
892  }
893 
894  {
895  std::vector< double > valid_directions;
896  {
897  std::vector< double > edited_ir_directions;
898  edited_ir_directions.reserve( dirs.size() );
899  for(size_t i = 0; i < dirs.size(); i++ )
900  {
901  auto val = double( *( dirs.begin() + i ) );
902  val = val + 1; // +1 to align with matlab
903  val = val > 4 ? val - 4 : val;
904  edited_ir_directions.push_back( val );
905  }
906  depth_filter( valid_directions,
907  edited_ir_directions,
909  1,
910  _z.supressed_edges.size() );
911  }
912  depth_filter( _z.directions, valid_directions, is_inside, 1, is_inside.size() );
913  if( _debug_mode )
914  _z.valid_directions = std::move( valid_directions );
915  }
916 
917  /*xim = xim(isInside);
918  yim = yim(isInside);
919  zValuesForSubEdges = zValuesForSubEdges(isInside);
920  zGradInDirection = zGradInDirection(isInside);
921  directionIndex = directionIndex(isInside);
922  weights = weights(isInside);
923  vertices = vertices(isInside,:);
924  sectionMapDepth = sectionMapDepth(isInside);*/
925  //std::vector<double> weights;
926 
927  {
928  std::vector< double > valid_weights;
929  valid_weights.reserve( is_inside.size() );
930  for(size_t i = 0; i < is_inside.size(); i++ )
931  valid_weights.push_back( _params.constant_weights );
932  depth_filter( _z.weights, valid_weights, is_inside, 1, is_inside.size() );
933  }
934 
935  transform(valid_edge_sub_pixel_x.begin(), valid_edge_sub_pixel_x.end(), valid_edge_sub_pixel_x.begin(), bind2nd(std::plus<double>(), -1.0));
936  transform(valid_edge_sub_pixel_y.begin(), valid_edge_sub_pixel_y.end(), valid_edge_sub_pixel_y.begin(), bind2nd(std::plus<double>(), -1.0));
937  depth_filter(_z.subpixels_x, valid_edge_sub_pixel_x, is_inside, 1, is_inside.size());
938  depth_filter(_z.subpixels_y, valid_edge_sub_pixel_y, is_inside, 1, is_inside.size());
939 
940  depth_filter(_z.closest, values_for_subedges, is_inside, 1, is_inside.size());
941 
942  _z.relevant_pixels_image.resize(_z.width * _z.height, 0);
943  std::vector< double > sub_pixel_x = _z.subpixels_x;
944  std::vector< double > sub_pixel_y = _z.subpixels_y;
945 
946  transform(_z.subpixels_x.begin(), _z.subpixels_x.end(), sub_pixel_x.begin(), [](double x) {return round(x + 1); });
947  transform(_z.subpixels_y.begin(), _z.subpixels_y.end(), sub_pixel_y.begin(), [](double x) {return round(x + 1); });
948 
949  for (size_t i = 0; i < sub_pixel_x.size(); i++)
950  {
951  auto x = sub_pixel_x[i];
952  auto y = sub_pixel_y[i];
953 
954  _z.relevant_pixels_image[size_t( ( y - 1 ) * _z.width + x - 1 )] = 1;
955  }
956 
957  if( _debug_mode )
958  {
959  _z.gradient_x = std::move( z_gradient_x );
960  _z.gradient_y = std::move( z_gradient_y );
961  _ir.gradient_x = std::move( ir_gradient_x );
962  _ir.gradient_y = std::move( ir_gradient_y );
963  _ir.edges = std::move( ir_edges );
964  _ir.valid_edge_pixels_by_ir = std::move( valid_edge_pixels_by_ir );
965  _z.section_map_depth = std::move( section_map_depth );
966  _ir.valid_section_map = std::move( valid_section_map );
967  _ir.valid_gradient_x = std::move( valid_gradient_x );
968  _ir.valid_gradient_y = std::move( valid_gradient_y );
969  _ir.valid_location_rc_x = std::move( valid_location_rc_x );
970  _ir.valid_location_rc_y = std::move( valid_location_rc_y );
971  _ir.valid_location_rc = std::move( valid_location_rc );
972  _ir.directions = std::move( dirs );
973  _ir.direction_per_pixel = std::move( direction_per_pixel );
974  _z.grad_in_direction = std::move( grad_in_direction );
975  _z.values_for_subedges = std::move( values_for_subedges );
976 
977  for (auto i = 0; i < 4; i++)
978  {
979  _ir.local_region[i] = std::move( local_region[i] );
980  _ir.local_region_x[i] = std::move( local_region_x[i] );
981  _ir.local_region_y[i] = std::move( local_region_y[i] );
982  }
983 
984  _z.is_inside = std::move( is_inside );
985  _z.subpixels_x_round = std::move( sub_pixel_x );
986  _z.subpixels_y_round = std::move( sub_pixel_y );
987  }
988 }
989 
990 
992  std::vector< yuy_t > && yuy_data,
993  std::vector< yuy_t > && prev_yuy_data,
994  std::vector< yuy_t > && last_successful_yuy_data,
995  calib const & calibration
996 )
997 {
998  _original_calibration = calibration;
1000  _yuy.width = calibration.width;
1001  _yuy.height = calibration.height;
1003 
1004  _yuy.orig_frame = std::move( yuy_data );
1005  _yuy.prev_frame = std::move( prev_yuy_data );
1006  _yuy.last_successful_frame = std::move( last_successful_yuy_data );
1007 
1008  std::vector< uint8_t > lum_frame;
1009  std::vector< uint8_t > prev_lum_frame;
1010  std::vector< uint8_t > last_successful_lum_frame;
1011 
1012  lum_frame = get_luminance_from_yuy2( _yuy.orig_frame );
1013  prev_lum_frame = get_luminance_from_yuy2( _yuy.prev_frame );
1014 
1015  auto edges = calc_edges( lum_frame, _yuy.width, _yuy.height );
1016 
1017  {
1018  auto prev_edges = calc_edges( prev_lum_frame, _yuy.width, _yuy.height );
1019 
1021  = is_movement_in_images( { prev_edges, prev_lum_frame },
1022  { edges, lum_frame },
1023  _debug_mode ? &_yuy.debug.movement_result : nullptr,
1026  _yuy.width, _yuy.height );
1027  }
1028 
1029  AC_LOG( DEBUG,
1030  " previous calibration image "
1031  << ( last_successful_yuy_data.empty() ? "was NOT supplied" : "supplied" ) );
1033  {
1034  last_successful_lum_frame = get_luminance_from_yuy2( _yuy.last_successful_frame );
1035  auto last_successful_edges = calc_edges( last_successful_lum_frame, _yuy.width, _yuy.height );
1036 
1038  { last_successful_edges, last_successful_lum_frame },
1039  { edges, lum_frame },
1043  _yuy.width, _yuy.height );
1044  }
1045  else
1047 
1048  _yuy.edges_IDT = blur_edges( edges, _yuy.width, _yuy.height );
1049  _yuy.edges_IDTx = calc_vertical_gradient( _yuy.edges_IDT, _yuy.width, _yuy.height );
1050  _yuy.edges_IDTy = calc_horizontal_gradient( _yuy.edges_IDT, _yuy.width, _yuy.height );
1051 
1052  // Get a map for each pixel to its corresponding section
1053  std::vector< byte > section_map_rgb( _yuy.width * _yuy.height );
1055  _params.num_of_sections_for_edge_distribution_x, //% params.numSectionsH
1056  _params.num_of_sections_for_edge_distribution_y, //% params.numSectionsV
1057  section_map_rgb.data() );
1058 
1059  // remove pixels in section map where rgbEdge <= params.gradRgbTh (see preprocessRGB)
1060  double const gradRgbTh = 15. * 1280 / _yuy.width;
1061  int i = 0;
1062  _yuy.section_map_edges.reserve( edges.size() );
1063  for( auto it = edges.begin(); it != edges.end(); ++it, ++i )
1064  {
1065  if( *it > gradRgbTh )
1066  _yuy.section_map_edges.push_back( section_map_rgb[i] );
1067  }
1068  _yuy.section_map_edges.shrink_to_fit();
1069  AC_LOG( DEBUG, " " << _yuy.section_map_edges.size() << " pixels with a relevant edge" );
1070 
1071  if( _debug_mode )
1072  {
1073  _yuy.debug.lum_frame = std::move( lum_frame );
1074  _yuy.debug.prev_lum_frame = std::move( prev_lum_frame );
1075  _yuy.debug.last_successful_lum_frame = std::move( last_successful_lum_frame );
1076 
1077  _yuy.debug.edges = std::move( edges );
1078  }
1079 }
1080 
1082  std::vector< ir_t > && ir_data,
1083  size_t width,
1084  size_t height
1085 )
1086 {
1087  _ir.width = width;
1088  _ir.height = height;
1089 
1090  _ir.ir_frame = std::move( ir_data );
1091 }
1092 
1094 {
1096  return calib;
1097 }
1098 
1099 
1101 {
1103  res = orig;
1104  res.fx = res.fx / new_c.k_mat.get_fx()*orig_c.k_mat.get_fx();
1105  res.fy = res.fy / new_c.k_mat.get_fy()*orig_c.k_mat.get_fy();
1106 
1107  return res;
1108 }
1109 
1110 std::vector< direction > optimizer::get_direction( std::vector<double> gradient_x, std::vector<double> gradient_y )
1111 {
1112  std::vector<direction> res( gradient_x.size(), deg_none );
1113 
1114  std::map<int, direction> angle_dir_map = { {0, deg_0}, {45,deg_45} , {90,deg_90}, {135,deg_135} };
1115 
1116  for(size_t i = 0; i < gradient_x.size(); i++ )
1117  {
1118  int closest = -1;
1119  auto angle = atan2( gradient_y[i], gradient_x[i] )* 180.f / M_PI;
1120  angle = angle < 0 ? 180 + angle : angle;
1121  auto dir = fmod( angle, 180 );
1122 
1123  for( auto d : angle_dir_map )
1124  {
1125  closest = closest == -1 || abs( dir - d.first ) < abs( dir - closest ) ? d.first : closest;
1126  }
1127  res[i] = angle_dir_map[closest];
1128  }
1129  return res;
1130 }
1131 std::vector< direction > optimizer::get_direction2(std::vector<double> gradient_x, std::vector<double> gradient_y)
1132 {
1133  std::vector<direction> res(gradient_x.size(), deg_none);
1134 
1135  std::map<int, direction> angle_dir_map = { {0, deg_0}, {45,deg_45} , {90,deg_90}, {135,deg_135} , { 180,deg_180 }, { 225,deg_225 }, { 270,deg_270 }, { 315,deg_315 } };
1136 
1137 
1138 
1139  for (size_t i = 0; i < gradient_x.size(); i++)
1140  {
1141  int closest = -1;
1142  auto angle = atan2(gradient_y[i], gradient_x[i]) * 180.f / M_PI;
1143  angle = angle < 0 ? 360 + angle : angle;
1144  auto dir = fmod(angle, 360);
1145 
1146  for (auto d : angle_dir_map)
1147  {
1148  closest = closest == -1 || abs(dir - d.first) < abs(dir - closest) ? d.first : closest;
1149  }
1150  res[i] = angle_dir_map[closest];
1151  }
1152  return res;
1153 }
1154 //std::vector< uint16_t > optimizer::get_closest_edges(
1155 // z_frame_data const & z_data,
1156 // ir_frame_data const & ir_data,
1157 // size_t width, size_t height )
1158 //{
1159 // std::vector< uint16_t > z_closest;
1160 // z_closest.reserve( z_data.edges.size() );
1161 //
1162 // for( auto i = 0; i < int(height); i++ )
1163 // {
1164 // for( auto j = 0; j < int(width); j++ )
1165 // {
1166 // auto idx = i * width + j;
1167 //
1168 // auto edge = z_data.edges[idx];
1169 //
1170 // //if (edge == 0) continue;
1171 //
1172 // auto edge_prev_idx = get_prev_index( z_data.valid_directions[idx], i, j, width, height );
1173 //
1174 // auto edge_next_idx = get_next_index( z_data.valid_directions[idx], i, j, width, height );
1175 //
1176 // auto edge_minus_idx = edge_prev_idx.second * width + edge_prev_idx.first;
1177 //
1178 // auto edge_plus_idx = edge_next_idx.second * width + edge_next_idx.first;
1179 //
1180 // auto z_edge_plus = z_data.edges[edge_plus_idx];
1181 // auto z_edge = z_data.edges[idx];
1182 // auto z_edge_minus = z_data.edges[edge_minus_idx];
1183 //
1184 //
1185 // if (z_data.supressed_edges[idx])
1186 // {
1187 // z_closest.push_back(std::min(z_data.frame[edge_minus_idx], z_data.frame[edge_plus_idx]));
1188 // }
1189 // else
1190 // {
1191 // z_closest.push_back(0);
1192 // }
1193 // }
1194 // }
1195 // return z_closest;
1196 //}
1197 
1198 /* Given pixel coordinates and depth in an image with no distortion or inverse distortion coefficients, compute the corresponding point in 3D space relative to the same camera */
1199 static void deproject_pixel_to_point(double point[3], const struct rs2_intrinsics_double * intrin, const double pixel[2], double depth)
1200 {
1201  double x = (double)(pixel[0] - intrin->ppx) / intrin->fx;
1202  double y = (double)(pixel[1] - intrin->ppy) / intrin->fy;
1203 
1204  point[0] = depth * x;
1205  point[1] = depth * y;
1206  point[2] = depth;
1207 }
1208 
1209 /* Given a point in 3D space, compute the corresponding pixel coordinates in an image with no distortion or forward distortion coefficients produced by the same camera */
1210 static void project_point_to_pixel(double pixel[2], const struct rs2_intrinsics_double * intrin, const double point[3])
1211 {
1212  double x = point[0] / point[2], y = point[1] / point[2];
1213 
1214  if( intrin->model == RS2_DISTORTION_BROWN_CONRADY )
1215  {
1216  double r2 = x * x + y * y;
1217  double f = 1 + intrin->coeffs[0] * r2 + intrin->coeffs[1] * r2*r2 + intrin->coeffs[4] * r2*r2*r2;
1218 
1219  double xcd = x * f;
1220  double ycd = y * f;
1221 
1222  double dx = xcd + 2 * intrin->coeffs[2] * x*y + intrin->coeffs[3] * (r2 + 2 * x*x);
1223  double dy = ycd + 2 * intrin->coeffs[3] * x*y + intrin->coeffs[2] * (r2 + 2 * y*y);
1224 
1225  x = dx;
1226  y = dy;
1227  }
1228 
1229  pixel[0] = x * (double)intrin->fx + (double)intrin->ppx;
1230  pixel[1] = y * (double)intrin->fy + (double)intrin->ppy;
1231 }
1232 
1233 std::vector<double> optimizer::blur_edges(std::vector<double> const & edges, size_t image_width, size_t image_height)
1234 {
1235  std::vector<double> res = edges;
1236 
1237  for(size_t i = 0; i < image_height; i++ )
1238  for(size_t j = 0; j < image_width; j++ )
1239  {
1240  if( i == 0 && j == 0 )
1241  continue;
1242  else if( i == 0 )
1243  res[j] = std::max( res[j], res[j - 1] * _params.gamma );
1244  else if( j == 0 )
1245  res[i*image_width + j] = std::max(
1246  res[i*image_width + j],
1247  res[(i - 1)*image_width + j] * _params.gamma );
1248  else
1249  res[i*image_width + j] = std::max(
1250  res[i*image_width + j],
1251  std::max(
1252  res[ i *image_width + j - 1] * _params.gamma,
1253  res[(i - 1)*image_width + j ] * _params.gamma ) );
1254  }
1255 
1256 
1257  for( int i = int(image_height) - 1; i >= 0; i-- ) // note: must be signed because will go under 0!
1258  for( int j = int(image_width) - 1; j >= 0; j-- )
1259  {
1260  if( i == image_height - 1 && j == image_width - 1 )
1261  continue;
1262  else if( i == image_height - 1 )
1263  res[i*image_width + j] = std::max( res[i*image_width + j], res[i*image_width + j + 1] * _params.gamma );
1264  else if( j == image_width - 1 )
1265  res[i*image_width + j] = std::max( res[i*image_width + j], res[(i + 1)*image_width + j] * _params.gamma );
1266  else
1267  res[i*image_width + j] = std::max( res[i*image_width + j], (std::max( res[i*image_width + j + 1] * _params.gamma, res[(i + 1)*image_width + j] * _params.gamma )) );
1268  }
1269 
1270  for(size_t i = 0; i < image_height; i++ )
1271  for(size_t j = 0; j < image_width; j++ )
1272  res[i*image_width + j] = _params.alpha * edges[i*image_width + j] + (1 - _params.alpha) * res[i*image_width + j];
1273  return res;
1274 }
1275 
1276 
1277 std::vector< byte > optimizer::get_luminance_from_yuy2( std::vector< yuy_t > const & yuy2_imagh )
1278 {
1279  std::vector<byte> res( yuy2_imagh.size(), 0 );
1280  auto yuy2 = (uint8_t*)yuy2_imagh.data();
1281  for(size_t i = 0; i < res.size(); i++ )
1282  res[i] = yuy2[i * 2];
1283 
1284  return res;
1285 }
1286 
1287 std::vector< uint8_t > optimizer::get_logic_edges( std::vector< double > const & edges )
1288 {
1289  std::vector<uint8_t> logic_edges( edges.size(), 0 );
1290  auto max = std::max_element( edges.begin(), edges.end() );
1291  auto thresh = *max * _params.edge_thresh4_logic_lum;
1292 
1293  for(size_t i = 0; i < edges.size(); i++ )
1294  {
1295  logic_edges[i] = abs( edges[i] ) > thresh ? 1 : 0;
1296  }
1297  return logic_edges;
1298 }
1299 
1300 
1301 
1303  std::vector< double > & sum_weights_per_section,
1304  std::vector< byte > const & section_map,
1305  std::vector< double > const & weights,
1306  size_t num_of_sections
1307 )
1308 {/*sumWeightsPerSection = zeros(params.numSectionsV*params.numSectionsH,1);
1309 for ix = 1:params.numSectionsV*params.numSectionsH
1310  sumWeightsPerSection(ix) = sum(weights(sectionMap == ix-1));
1311 end*/
1312  if( section_map.size() != weights.size() )
1313  throw std::runtime_error( to_string()
1314  << "unexpected size for section_map (" << section_map.size()
1315  << ") vs weights (" << weights.size() << ")" );
1316  sum_weights_per_section.resize( num_of_sections );
1317  auto p_sum = sum_weights_per_section.data();
1318  for( byte i = 0; i < num_of_sections; ++i, ++p_sum )
1319  {
1320  *p_sum = 0;
1321 
1322  auto p_section = section_map.data();
1323  auto p_weight = weights.data();
1324  for( size_t ii = 0; ii < section_map.size(); ++ii, ++p_section, ++p_weight )
1325  {
1326  if( *p_section == i )
1327  *p_sum += *p_weight;
1328  }
1329  }
1330 }
1331 
1332 
1333 double get_max(double x, double y)
1334 {
1335  return x > y ? x : y;
1336 }
1337 double get_min(double x, double y)
1338 {
1339  return x < y ? x : y;
1340 }
1341 
1342 //std::vector<double> optimizer::calculate_weights(z_frame_data& z_data)
1343 //{
1344 // std::vector<double> res;
1345 //
1346 // for (auto i = 0; i < z_data.supressed_edges.size(); i++)
1347 // {
1348 // if (z_data.supressed_edges[i])
1349 // z_data.weights.push_back(
1350 // get_min(get_max(z_data.supressed_edges[i] - _params.grad_z_min, (double)0),
1351 // _params.grad_z_max - _params.grad_z_min));
1352 // }
1353 //
1354 // return res;
1355 //}
1356 
1358  std::vector<double3>& points,
1360  std::vector< byte > const & valid_edges,
1361  const double* x,
1362  const double* y,
1363  const double* depth, double depth_units
1364 )
1365 {
1366  auto ptr = (double*)points.data();
1367  byte const * valid_edge = valid_edges.data();
1368  for (size_t i = 0; i < valid_edges.size(); ++i)
1369  {
1370  if (!valid_edge[i])
1371  continue;
1372 
1373  const double pixel[] = { x[i] - 1, y[i] - 1 };
1374  deproject_pixel_to_point(ptr, &intrin, pixel, depth[i] * depth_units);
1375  ptr += 3;
1376  }
1377 }
1378 
1380 {
1381  std::vector<double3> res(z_data.n_strong_edges);
1382  deproject_sub_pixel(res, intrin, z_data.supressed_edges, z_data.subpixels_x.data(), z_data.subpixels_y.data(), z_data.closest.data(), depth_units);
1383  z_data.vertices = res;
1384  return res;
1385 }
1386 
1387 static p_matrix calc_p_gradients(const z_frame_data & z_data,
1388  const std::vector<double3>& new_vertices,
1389  const yuy2_frame_data & yuy_data,
1390  std::vector<double> interp_IDT_x,
1391  std::vector<double> interp_IDT_y,
1392  const calib & cal,
1393  const p_matrix & p_mat,
1394  const std::vector<double>& rc,
1395  const std::vector<double2>& xy,
1396  data_collect * data = nullptr)
1397 {
1398  auto coefs = calc_p_coefs(z_data, new_vertices, yuy_data, cal, p_mat, rc, xy);
1399  auto w = z_data.weights;
1400 
1401  if (data)
1402  data->iteration_data_p.coeffs_p = coefs;
1403 
1404  p_matrix sums = { 0 };
1405  auto sum_of_valids = 0;
1406 
1407  for (size_t i = 0; i < coefs.x_coeffs.size(); i++)
1408  {
1409  if (interp_IDT_x[i] == std::numeric_limits<double>::max() || interp_IDT_y[i] == std::numeric_limits<double>::max())
1410  continue;
1411 
1412  sum_of_valids++;
1413 
1414  for (auto j = 0; j < 12; j++)
1415  {
1416  sums.vals[j] += w[i] * (interp_IDT_x[i] * coefs.x_coeffs[i].vals[j] + interp_IDT_y[i] * coefs.y_coeffs[i].vals[j]);
1417  }
1418 
1419  }
1420 
1421  p_matrix averages = { 0 };
1422  for (auto i = 0; i < 8; i++) //zero the last line of P grad?
1423  {
1424  averages.vals[i] = (double)sums.vals[i] / (double)sum_of_valids;
1425  }
1426 
1427  return averages;
1428 }
1429 
1430 static
1431 std::pair< std::vector<double2>, std::vector<double>> calc_rc(
1432  const z_frame_data & z_data,
1433  const std::vector<double3>& new_vertices,
1434  const yuy2_frame_data & yuy_data,
1435  const calib & cal,
1436  const p_matrix & p_mat
1437 )
1438 {
1439  auto v = new_vertices;
1440 
1441  std::vector<double2> f1( z_data.vertices.size() );
1442  std::vector<double> r2( z_data.vertices.size() );
1443  std::vector<double> rc( z_data.vertices.size() );
1444 
1445  auto yuy_intrin = cal.get_intrinsics();
1446  auto yuy_extrin = cal.get_extrinsics();
1447 
1448  auto fx = (double)yuy_intrin.fx;
1449  auto fy = (double)yuy_intrin.fy;
1450  auto ppx = (double)yuy_intrin.ppx;
1451  auto ppy = (double)yuy_intrin.ppy;
1452 
1453  /* double mat[3][4] = {
1454  fx*(double)r[0] + ppx * (double)r[2], fx*(double)r[3] + ppx * (double)r[5], fx*(double)r[6] + ppx * (double)r[8], fx*(double)t[0] + ppx * (double)t[2],
1455  fy*(double)r[1] + ppy * (double)r[2], fy*(double)r[4] + ppy * (double)r[5], fy*(double)r[7] + ppy * (double)r[8], fy*(double)t[1] + ppy * (double)t[2],
1456  r[2], r[5], r[8], t[2] };
1457 */
1458  auto mat = p_mat.vals;
1459  for(size_t i = 0; i < z_data.vertices.size(); ++i )
1460  {
1461  double x = v[i].x;
1462  double y = v[i].y;
1463  double z = v[i].z;
1464 
1465  double x1 = (double)mat[0] * (double)x + (double)mat[1] * (double)y + (double)mat[2] * (double)z + (double)mat[3];
1466  double y1 = (double)mat[4] * (double)x + (double)mat[5] * (double)y + (double)mat[6] * (double)z + (double)mat[7];
1467  double z1 = (double)mat[8] * (double)x + (double)mat[9] * (double)y + (double)mat[10] * (double)z + (double)mat[11];
1468 
1469  auto x_in = x1 / z1;
1470  auto y_in = y1 / z1;
1471 
1472  auto x2 = ((x_in - ppx) / fx);
1473  auto y2 = ((y_in - ppy) / fy);
1474 
1475  f1[i].x = x2;
1476  f1[i].y = y2;
1477 
1478  auto r2 = (x2 * x2 + y2 * y2);
1479 
1480  rc[i] = 1 + (double)yuy_intrin.coeffs[0] * r2 + (double)yuy_intrin.coeffs[1] * r2 * r2 + (double)yuy_intrin.coeffs[4] * r2 * r2 * r2;
1481  }
1482 
1483  return { f1,rc };
1484 }
1485 
1487  const z_frame_data& z_data,
1488  const std::vector<double3>& new_vertices,
1489  const yuy2_frame_data& yuy_data,
1490  const std::vector<double2>& uv,
1491  const calib & cal,
1492  const p_matrix & p_mat,
1493  data_collect * data = nullptr
1494 )
1495 {
1496  p_matrix res;
1497  auto interp_IDT_x = biliniar_interp( yuy_data.edges_IDTx, yuy_data.width, yuy_data.height, uv );
1498  auto interp_IDT_y = biliniar_interp( yuy_data.edges_IDTy, yuy_data.width, yuy_data.height, uv );
1499 
1500  auto rc = calc_rc( z_data, new_vertices, yuy_data, cal, p_mat);
1501 
1502  if (data)
1503  {
1504  data->iteration_data_p.d_vals_x = interp_IDT_x;
1505  data->iteration_data_p.d_vals_y = interp_IDT_y;
1506  data->iteration_data_p.xy = rc.first;
1507  data->iteration_data_p.rc = rc.second;
1508  }
1509 
1510  res = calc_p_gradients( z_data, new_vertices, yuy_data, interp_IDT_x, interp_IDT_y, cal, p_mat, rc.second, rc.first, data );
1511  return res;
1512 }
1513 
1514 std::pair<double, p_matrix> calc_cost_and_grad(
1515  const z_frame_data & z_data,
1516  const std::vector<double3>& new_vertices,
1517  const yuy2_frame_data & yuy_data,
1518  const calib & cal,
1519  const p_matrix & p_mat,
1520  data_collect * data = nullptr
1521 )
1522 {
1523  auto uvmap = get_texture_map(new_vertices, cal, p_mat);
1524  if( data )
1525  data->iteration_data_p.uvmap = uvmap;
1526 
1527  auto cost = calc_cost(z_data, yuy_data, uvmap, data ? &data->iteration_data_p.d_vals : nullptr );
1528  auto grad = calc_gradients(z_data, new_vertices, yuy_data, uvmap, cal, p_mat, data);
1529  return { cost, grad };
1530 }
1531 
1533 {
1534  normalize_mat.vals[0] = 0.353692440000000;
1535  normalize_mat.vals[1] = 0.266197740000000;
1536  normalize_mat.vals[2] = 1.00926010000000;
1537  normalize_mat.vals[3] = 0.000673204490000000;
1538  normalize_mat.vals[4] = 0.355085250000000;
1539  normalize_mat.vals[5] = 0.266275050000000;
1540  normalize_mat.vals[6] = 1.01145800000000;
1541  normalize_mat.vals[7] = 0.000675013750000000;
1542  normalize_mat.vals[8] = 414.205570000000;
1543  normalize_mat.vals[9] = 313.341060000000;
1544  normalize_mat.vals[10] = 1187.34590000000;
1545  normalize_mat.vals[11] = 0.791570250000000;
1546 
1547  // NOTE: until we know the resolution, the current state is just the default!
1548  // We need to get the depth and rgb resolutions to make final decisions!
1549 }
1551 {
1552 }
1554 {
1555 }
1556 void params::set_depth_resolution( size_t width, size_t height, rs2_digital_gain digital_gain)
1557 {
1558  AC_LOG( DEBUG, " depth resolution= " << width << "x" << height );
1559  // Some parameters are resolution-dependent
1560  bool const XGA = ( width == 1024 && height == 768 );
1561  bool const VGA = ( width == 640 && height == 480 );
1562 
1563  if( ! XGA && ! VGA )
1564  {
1565  throw std::runtime_error( to_string() << width << "x" << height
1566  << " this resolution is not supported" );
1567  }
1568 
1569  if( XGA )
1570  {
1571  AC_LOG( DEBUG, " changing IR threshold: " << grad_ir_threshold << " -> " << 2.5 << " (because of resolution)" );
1572  grad_ir_threshold = 2.5;
1573  }
1574  if (use_enhanced_preprocessing)
1575  {
1576  if (digital_gain == RS2_DIGITAL_GAIN_HIGH)
1577  {
1578  if (VGA)
1579  {
1580  grad_ir_low_th = 1.5;
1581  grad_ir_high_th = 3.5;
1582  grad_z_low_th = 0;
1583  grad_z_high_th = 100;
1584  }
1585  else if (XGA)
1586  {
1587  grad_ir_low_th = 1;
1588  grad_ir_high_th = 2.5;
1589  grad_z_low_th = 0;
1590  grad_z_high_th = 80;
1591  }
1592  }
1593  else
1594  {
1595  if (VGA)
1596  {
1597  grad_ir_low_th = std::numeric_limits<double>::max();
1598  grad_ir_high_th = 3.5;
1599  grad_z_low_th = 0;
1600  grad_z_high_th = std::numeric_limits<double>::max();
1601  }
1602  else if (XGA)
1603  {
1604  grad_ir_low_th = std::numeric_limits<double>::max();
1605  grad_ir_high_th = 2.5;
1606  grad_z_low_th = 0;
1607  grad_z_high_th = std::numeric_limits<double>::max();
1608  }
1609  }
1610  }
1611 
1612  min_weighted_edge_per_section_depth = 50. * ( 480 * 640 ) / ( width * height );
1613 }
1614 
1616 {
1617  AC_LOG( DEBUG, " RGB resolution= " << width << "x" << height );
1618  auto area = width * height;
1619  size_t const hd_area = 1920 * 1080;
1620  move_threshold_pix_num = 3e-5 * area;
1621  move_last_success_thresh_pix_num = 0.1 * area;
1622  max_xy_movement_per_calibration[0] = 10. * area / hd_area;
1623  max_xy_movement_per_calibration[1] = max_xy_movement_per_calibration[2] = 2. * area / hd_area;
1624  max_xy_movement_from_origin = 20. * area / hd_area;
1625  min_weighted_edge_per_section_rgb = 0.05 * hd_area / area;
1626 
1627 }
1628 
1630 {
1631  return _final_calibration;
1632 }
1633 
1635 {
1636  return _final_dsm_params;
1637 }
1638 
1639 double optimizer::get_cost() const
1640 {
1641  return _params_curr.cost;
1642 }
1643 
1644 
1645 
1646 template< typename T >
1647 void write_obj( std::fstream & f, T const & o )
1648 {
1649  f.write( (char const *)&o, sizeof( o ) );
1650 }
1651 
1653  rs2_intrinsics const & _intr_depth,
1654  calib const & rgb_calibration,
1655  float _depth_units,
1656  std::string const & dir,
1657  char const * filename
1658 )
1659 {
1660  std::string path = dir + filename;
1661  std::fstream f( path, std::ios::out | std::ios::binary );
1662  if( !f )
1663  throw std::runtime_error( "failed to open file:\n" + path );
1664 
1665 
1666  //depth intrinsics
1667  write_obj( f, (double)_intr_depth.width );
1668  write_obj( f, (double)_intr_depth.height );
1669  write_obj( f, (double)1/_depth_units );
1670 
1671  double k_depth[9] = { _intr_depth.fx, 0, _intr_depth.ppx,
1672  0, _intr_depth.fy, _intr_depth.ppy,
1673  0, 0, 1 };
1674  for( auto i = 0; i < 9; i++ )
1675  {
1676  write_obj( f, k_depth[i] );
1677  }
1678 
1679  //color intrinsics
1680  rs2_intrinsics _intr_rgb = rgb_calibration.get_intrinsics();
1681 
1682  write_obj( f, (double)_intr_rgb.width );
1683  write_obj( f, (double)_intr_rgb.height );
1684 
1685  double k_rgb[9] = { _intr_rgb.fx, 0, _intr_rgb.ppx,
1686  0, _intr_rgb.fy, _intr_rgb.ppy,
1687  0, 0, 1 };
1688 
1689 
1690  for( auto i = 0; i < 9; i++ )
1691  {
1692  write_obj( f, k_rgb[i] );
1693  }
1694 
1695  for( auto i = 0; i < 5; i++ )
1696  {
1697  write_obj( f, (double)_intr_rgb.coeffs[i] );
1698  }
1699 
1700  //extrinsics
1701  rs2_extrinsics _extr = rgb_calibration.get_extrinsics();
1702  for( auto i = 0; i < 9; i++ )
1703  {
1704  write_obj( f, (double)_extr.rotation[i] );
1705  }
1706  //extrinsics
1707  for( auto i = 0; i < 3; i++ )
1708  {
1709  write_obj( f, (double)_extr.rotation[i] );
1710  }
1711 
1712  f.close();
1713 }
1714 
1716 {
1717  // NOTE: it is expected that dir ends with a path separator or this won't work!
1718  AC_LOG( DEBUG, " writing data to: " << dir );
1719 
1720  try
1721  {
1722  write_vector_to_file( _yuy.orig_frame, dir, "rgb.raw" );
1723  write_vector_to_file( _yuy.prev_frame, dir, "rgb_prev.raw" );
1724  write_vector_to_file( _yuy.last_successful_frame, dir, "rgb_last_successful.raw");
1725  write_vector_to_file( _ir.ir_frame, dir, "ir.raw" );
1726  write_vector_to_file( _z.frame, dir, "depth.raw" );
1727 
1728  write_to_file( &_original_dsm_params, sizeof( _original_dsm_params ), dir, "dsm.params" );
1729  write_to_file( &_original_calibration, sizeof( _original_calibration ), dir, "rgb.calib" );
1730  auto & cal_info = _k_to_DSM->get_calibration_info();
1731  auto & cal_regs = _k_to_DSM->get_calibration_registers();
1732  write_to_file( &cal_info, sizeof( cal_info ), dir, "cal.info" );
1733  write_to_file( &cal_regs, sizeof( cal_regs ), dir, "cal.registers" );
1734  write_to_file( &_z.orig_intrinsics, sizeof( _z.orig_intrinsics), dir, "depth.intrinsics" );
1735  write_to_file( &_z.depth_units, sizeof( _z.depth_units ), dir, "depth.units" );
1736  write_to_file( &_settings, sizeof( _settings ), dir, "settings" );
1737 
1738  // This file is meant for matlab -- it packages all the information needed
1741  _z.depth_units,
1742  dir,
1743  "camera_params"
1744  );
1745  }
1746  catch( std::exception const & err )
1747  {
1748  AC_LOG( ERROR, "Failed to write data: " << err.what() );
1749  }
1750  catch( ... )
1751  {
1752  AC_LOG( ERROR, "Failed to write data (unknown error)" );
1753  }
1754 }
1755 
1757  const std::vector<double3>& new_vertices,
1758  data_collect * data ) const
1759 {
1760  optimization_params new_params;
1761 
1762  // was gradStruct.P ./ norm( gradStruct.P(:) ) -> vector norm
1763  // now gradStruct.P ./ norm( gradStruct.P ) -> matrix 2-norm
1764  auto grads_over_norm
1765  = curr_params.calib_gradients.normalize( curr_params.calib_gradients.matrix_norm() );
1766  //%grad = gradStruct.P ./ norm(gradStruct.P) ./ params.rgbPmatNormalizationMat;
1767  auto grad = grads_over_norm / _params.normalize_mat;
1768 
1769  //%unitGrad = grad ./ norm(grad); <- was ./ norm(grad(:)')
1770  auto grad_norm = grad.matrix_norm();
1771  auto unit_grad = grad.normalize( grad_norm );
1772 
1773  //%t = -params.controlParam * grad(:)' * unitGrad(:);
1774  // -> dot product of grad and unitGrad
1775  auto t_vals = ( grad * -_params.control_param ) * unit_grad;
1776  auto t = t_vals.sum();
1777 
1778  //%stepSize = params.maxStepSize * norm(grad) / norm(unitGrad);
1779  auto step_size = _params.max_step_size * grad_norm / unit_grad.matrix_norm();
1780 
1781 
1782  auto movement = unit_grad * step_size;
1783  new_params.curr_p_mat = curr_params.curr_p_mat + movement;
1784 
1785  calib old_calib = decompose( curr_params.curr_p_mat, _original_calibration );
1786  auto uvmap_old = get_texture_map(new_vertices, old_calib, curr_params.curr_p_mat );
1787  //curr_params.cost = calc_cost( z_data, yuy_data, uvmap_old );
1788 
1789  calib new_calib = decompose( new_params.curr_p_mat, _original_calibration );
1790  auto uvmap_new = get_texture_map(new_vertices, new_calib, new_params.curr_p_mat );
1791  new_params.cost = calc_cost( _z, _yuy, uvmap_new );
1792 
1793  auto diff = calc_cost_per_vertex_diff( _z, _yuy, uvmap_old, uvmap_new );
1794 
1795  auto iter_count = 0;
1796  while( diff >= step_size * t
1797  && abs( step_size ) > _params.min_step_size
1798  && iter_count++ < _params.max_back_track_iters )
1799  {
1800  //AC_LOG( DEBUG, " back tracking line search cost= " << AC_D_PREC << new_params.cost );
1801  step_size = _params.tau * step_size;
1802 
1803  new_params.curr_p_mat = curr_params.curr_p_mat + unit_grad * step_size;
1804 
1805  new_calib = decompose( new_params.curr_p_mat, _original_calibration );
1806  uvmap_new = get_texture_map(new_vertices, new_calib, new_params.curr_p_mat);
1807  new_params.cost = calc_cost( _z, _yuy, uvmap_new);
1808  diff = calc_cost_per_vertex_diff( _z, _yuy, uvmap_old, uvmap_new );
1809  }
1810 
1811  if(diff >= step_size * t )
1812  {
1813  new_params = curr_params;
1814  }
1815 
1816  if (data)
1817  {
1818  data->iteration_data_p.grads_norma = curr_params.calib_gradients.get_norma();
1819  data->iteration_data_p.grads_norm = grads_over_norm;
1820  data->iteration_data_p.normalized_grads = grad;
1821  data->iteration_data_p.unit_grad = unit_grad;
1823  data->iteration_data_p.t = t;
1824  }
1825  return new_params;
1826 }
1827 
1828 void optimizer::set_final_data(const std::vector<double3>& vertices,
1829  const p_matrix& p_mat,
1830  const p_matrix& p_mat_opt)
1831 {
1833  _p_mat_from_bin = p_mat;
1834  _p_mat_from_bin_opt = p_mat_opt;
1835 }
1836 
1837 void optimizer::set_cycle_data(const std::vector<double3>& vertices,
1838  const rs2_intrinsics_double& k_depth,
1839  const p_matrix& p_mat,
1840  const algo_calibration_registers& dsm_regs_cand,
1841  const rs2_dsm_params_double& dsm_params_cand)
1842 {
1844  _k_dapth_from_bin = k_depth;
1845  _p_mat_from_bin = p_mat;
1846  _dsm_regs_cand_from_bin = dsm_regs_cand;
1847  _dsm_params_cand_from_bin = dsm_params_cand;
1848 }
1849 
1851 {
1852  if(_settings.digital_gain == RS2_DIGITAL_GAIN_HIGH) // long preset
1853  _params.saturation_value = 230;
1854  else if(_settings.digital_gain == RS2_DIGITAL_GAIN_LOW) // short preset
1855  _params.saturation_value = 250;
1856  else
1857  throw std::runtime_error(to_string() << _settings.digital_gain << " invalid digital gain value");
1858 }
1859 
1861 {
1868 
1869  const static double newvals[N_BASIC_DIRECTIONS] = { 0.09,0.09,0.09,0.09 };
1870  std::copy(std::begin(newvals), std::end(newvals), std::begin(_params.dir_std_th));
1873 }
1874 
1876 {
1883 
1884  const static double newvals[N_BASIC_DIRECTIONS] = { 0.09,0.09,0.09,0.09 };
1885  std::copy(std::begin(newvals), std::end(newvals), std::begin(_params.dir_std_th));
1888 }
1889 
1890 size_t optimizer::optimize_p
1892  const optimization_params& params_curr,
1893  const std::vector<double3>& new_vertices,
1894  optimization_params& params_new,
1895  calib& optimaized_calibration,
1896  calib& new_rgb_calib_for_k_to_dsm,
1897  rs2_intrinsics_double& new_z_k,
1898  std::function<void(data_collect const&data)> cb,
1899  data_collect& data )
1900 {
1901  // The params_curr that we get contains a cost and p_matrix that do not match:
1902  // The cost is the optimal cost calculated in the previous cycle, but we don't use it here.
1903  // The p_matrix is the optimal p_matrix that has been modified (see the end of this function).
1904  // Between the previous cycle and now we have new vertices so we recalculate a new cost based
1905  // on the modified p_matrix and the new vertices
1906  size_t n_iterations = 0;
1907  auto curr = params_curr;
1908  while (1)
1909  {
1910 
1911  auto res = calc_cost_and_grad(_z, new_vertices, _yuy, new_rgb_calib_for_k_to_dsm, curr.curr_p_mat, &data);
1912  curr.cost = res.first;
1913  curr.calib_gradients = res.second;
1914  AC_LOG( DEBUG, std::setw( 3 ) << std::right << n_iterations << std::left
1915  << " cost= " << AC_D_PREC << curr.cost );
1916 
1917  data.iteration_data_p.iteration = n_iterations;
1918  if( _debug_mode )
1919  {
1920 
1921  data.iteration_data_p.params = curr;
1922  data.iteration_data_p.c = new_rgb_calib_for_k_to_dsm;
1923  data.iteration_data_p.iteration = n_iterations;
1924  }
1925 
1926  params_new = back_tracking_line_search( curr, new_vertices, &data );
1927 
1928  if( _debug_mode )
1929  data.iteration_data_p.next_params = params_new;
1930 
1932  if( cb )
1933  cb(data);
1934 
1935 
1936  auto norm = (params_new.curr_p_mat - curr.curr_p_mat).get_norma();
1937  if (norm < _params.min_rgb_mat_delta)
1938  {
1939  AC_LOG(DEBUG, " {normal(new-curr)} " << norm << " < " << _params.min_rgb_mat_delta << " {min_rgb_mat_delta} --> stopping");
1940  break;
1941  }
1942 
1943  auto delta = params_new.cost - curr.cost;
1944  //AC_LOG( DEBUG, " delta= " << AC_D_PREC << delta );
1945  delta = abs(delta);
1946  if (delta < _params.min_cost_delta)
1947  {
1948  AC_LOG(DEBUG, " delta < " << _params.min_cost_delta << " --> stopping");
1949  break;
1950  }
1951 
1952  if (++n_iterations >= _params.max_optimization_iters)
1953  {
1954  AC_LOG(DEBUG, " exceeding max iterations --> stopping");
1955  break;
1956  }
1957 
1958  curr = params_new;
1959  new_rgb_calib_for_k_to_dsm = decompose_p_mat(params_new.curr_p_mat);
1960  }
1961 
1962  AC_LOG( DEBUG,
1963  " optimize_p finished after " << n_iterations << " iterations; cost "
1964  << AC_D_PREC << params_curr.cost << " --> " << params_new.cost );
1965  new_rgb_calib_for_k_to_dsm = optimaized_calibration = decompose_p_mat(params_new.curr_p_mat);
1966 
1967  new_rgb_calib_for_k_to_dsm.k_mat.k_mat.rot[1] = 0; //sheer
1968 
1969  new_z_k = get_new_z_intrinsics_from_new_calib(_z.orig_intrinsics, new_rgb_calib_for_k_to_dsm, _original_calibration);
1970  new_rgb_calib_for_k_to_dsm.k_mat.k_mat.rot[0] = _original_calibration.k_mat.get_fx();
1971  new_rgb_calib_for_k_to_dsm.k_mat.k_mat.rot[4] = _original_calibration.k_mat.get_fy();
1972  params_new.curr_p_mat = new_rgb_calib_for_k_to_dsm.calc_p_mat();
1973 
1974  return n_iterations;
1975 }
1976 
1977 size_t optimizer::optimize( std::function< void( data_collect const & data ) > cb )
1978 {
1979  optimization_params params_orig;
1981  _params_curr = params_orig;
1982 
1984 
1985  auto cycle = 1;
1986  data.cycle_data_p.cycle = cycle;
1987 
1988  auto res = calc_cost_and_grad( _z,
1989  _z.vertices,
1990  _yuy,
1993  _debug_mode? &data: nullptr );
1994 
1995  _params_curr.cost = res.first;
1996  _params_curr.calib_gradients = res.second;
1997  params_orig.cost = res.first;
1998 
1999  optimization_params new_params;
2000  calib new_calib = _original_calibration;
2001  calib new_k_to_dsm_calib = _original_calibration;
2002  rs2_intrinsics_double new_k_depth;
2003  algo_calibration_registers new_dsm_regs = _k_to_DSM->get_calibration_registers();
2004  auto new_vertices = _z.vertices;
2005 
2006  double last_cost = _params_curr.cost;
2007 
2008  auto n_iterations = optimize_p( _params_curr,
2009  new_vertices,
2010  new_params,
2012  new_calib,
2013  new_k_depth,
2014  cb,
2015  data );
2016 
2018  rs2_dsm_params_double new_dsm_params = _z.orig_dsm_params;
2019 
2020  while (cycle-1 < _params.max_K2DSM_iters)
2021  {
2022  std::vector<double3> cand_vertices = _z.vertices;
2023  auto dsm_regs_cand = new_dsm_regs;
2024 
2025  optimization_params params_candidate = new_params;
2026  calib calib_candidate = new_calib;
2027  calib calib_k_to_dsm_candidate = new_calib;
2028  calib optimaized_calib_candidate = _optimaized_calibration;
2029  rs2_intrinsics_double k_depth_candidate = new_k_depth;
2030 
2031  ++cycle;
2032  data.cycle_data_p.cycle = cycle;
2033 
2034  if (_debug_mode)
2035  {
2036  data.cycle_data_p.new_calib = new_calib;
2037  data.cycle_data_p.new_k_depth = new_k_depth;
2038  data.cycle_data_p.new_params = new_params;
2039  data.cycle_data_p.new_dsm_params = new_dsm_params;
2040  data.cycle_data_p.new_dsm_regs = new_dsm_regs;
2041  data.cycle_data_p.new_vertices = new_vertices;
2042  data.cycle_data_p.optimaized_calib_candidate = optimaized_calib_candidate;
2043 
2044  }
2045 
2046  if( cb )
2047  {
2048  data.type = _debug_mode ? cycle_data : general_data;
2049  cb( data );
2050  }
2051 
2052  AC_LOG(INFO, "CYCLE " << data.cycle_data_p.cycle << " started with: cost = " << AC_D_PREC << new_params.cost);
2053 
2054 
2056  {
2057  new_params.curr_p_mat = _p_mat_from_bin;
2059  new_k_depth = _k_dapth_from_bin;
2060  new_dsm_regs = _dsm_regs_cand_from_bin;
2061  new_dsm_params = _dsm_params_cand_from_bin;
2062  }
2063 
2064  auto dsm_candidate = _k_to_DSM->convert_new_k_to_DSM( _z.orig_intrinsics,
2065  new_k_depth,
2066  _z,
2067  cand_vertices,
2068  new_dsm_params,
2069  dsm_regs_cand,
2070  _debug_mode ? &data : nullptr );
2071  //data.type = cycle_data;
2072 
2073  //this calib is now candidate to be the optimaized we can confirm it only after running more optimize_p
2074  calib_k_to_dsm_candidate = calib_candidate;
2075 
2076  if (_debug_mode)
2077  {
2078  data.k2dsm_data_p.dsm_params_cand = dsm_candidate;
2079  data.k2dsm_data_p.vertices = cand_vertices;
2080  data.k2dsm_data_p.dsm_pre_process_data = _k_to_DSM->get_pre_process_data();
2081 
2082  if( cb )
2083  {
2084  data.type = k_to_dsm_data;
2085  cb(data);
2086  }
2087  }
2088 
2089 
2090  optimize_p( new_params,
2091  cand_vertices,
2092  params_candidate,
2093  optimaized_calib_candidate,
2094  calib_candidate,
2095  k_depth_candidate,
2096  cb,
2097  data );
2098 
2099  if( params_candidate.cost < last_cost )
2100  {
2101  if (cycle == 2)
2102  {// No change at all (probably very good starting point)
2103  AC_LOG(DEBUG, "No change required (probably very good starting point)");
2104  new_k_to_dsm_calib = new_calib;
2106  }
2107 
2108  AC_LOG( DEBUG, " cost is a regression; stopping -- not using last cycle" );
2109  break;
2110  }
2111 
2112  new_params = params_candidate;
2113  _params_curr = new_params;
2114  new_calib = calib_candidate;
2115  new_k_to_dsm_calib = calib_k_to_dsm_candidate;
2116  new_k_depth = k_depth_candidate;
2117  new_dsm_params = dsm_candidate;
2118  new_dsm_regs = dsm_regs_cand;
2119  last_cost = new_params.cost;
2120  new_vertices = cand_vertices;
2121  _z.vertices = new_vertices;
2122  _optimaized_calibration = optimaized_calib_candidate;
2123  }
2124 
2125  AC_LOG( INFO,
2126  "Calibration converged; cost " << AC_D_PREC << params_orig.cost << " --> "
2127  << new_params.cost );
2128 
2130  clip_ac_scaling( _z.orig_dsm_params, new_dsm_params );
2131  new_dsm_params.copy_to( _final_dsm_params );
2133 
2134  _final_calibration = new_k_to_dsm_calib;
2135 
2136  // The actual valid cycles - we starting from 1 and the last cycle is only for verification
2137  return cycle - 2;
2138 }
orig
Definition: rmse.py:46
GLuint GLuint end
bool is_movement_in_images(movement_inputs_for_frame const &prev, movement_inputs_for_frame const &curr, movement_result_data *result_data, double const move_thresh_pix_val, double const move_threshold_pix_num, size_t width, size_t height)
rs2_extrinsics_double get_extrinsics() const
Definition: calibration.cpp:63
void set_rgb_resolution(size_t width, size_t height)
Definition: optimizer.cpp:1615
GLint y
float calc_intensity(const cv::Mat &src)
static void deproject_pixel_to_point(double point[3], const struct rs2_intrinsics_double *intrin, const double pixel[2], double depth)
Definition: optimizer.cpp:1199
const GLbyte * weights
Definition: glext.h:4709
static p_matrix calc_gradients(const z_frame_data &z_data, const std::vector< double3 > &new_vertices, const yuy2_frame_data &yuy_data, const std::vector< double2 > &uv, const calib &cal, const p_matrix &p_mat, data_collect *data=nullptr)
Definition: optimizer.cpp:1486
void write_to_file(void const *data, size_t cb, std::string const &dir, char const *filename)
static std::vector< double > depth_mean(std::vector< double > const &local_x, std::vector< double > const &local_y)
Definition: optimizer.cpp:360
GLdouble s
static std::vector< double > get_direction_deg(std::vector< double > const &gradient_x, std::vector< double > const &gradient_y)
Definition: optimizer.cpp:143
GLfloat GLfloat p
Definition: glext.h:12687
const GLfloat * m
Definition: glext.h:6814
static std::vector< double > find_local_values_min(std::vector< double > const &local_values)
Definition: optimizer.cpp:435
void set_depth_resolution(size_t width, size_t height, rs2_digital_gain digital_gain)
Definition: optimizer.cpp:1556
GLdouble GLdouble GLdouble y2
Video DSM (Digital Sync Module) parameters for calibration (same layout as in FW ac_depth_params) Thi...
Definition: rs_types.h:74
size_t optimize_p(const optimization_params &params_curr, const std::vector< double3 > &new_vertices, optimization_params &params_new, calib &optimaized_calibration, calib &new_rgb_calib_for_k_to_dsm, rs2_intrinsics_double &new_z_k, std::function< void(data_collect const &data)> cb, data_collect &data)
Definition: optimizer.cpp:1891
GLsizei const GLchar *const * path
Definition: glext.h:4276
void set_final_data(const std::vector< double3 > &vertices, const p_matrix &p_mat, const p_matrix &p_mat_opt=p_matrix())
Definition: optimizer.cpp:1828
GLint GLuint mask
rs2_intrinsics_double get_intrinsics() const
Definition: calibration.cpp:55
std::vector< double > interpolation(std::vector< T > const &grid_points, std::vector< double > const x[], std::vector< double > const y[], size_t dim, size_t valid_size, size_t valid_width)
Definition: optimizer.cpp:313
std::vector< double3 > subedges2vertices(z_frame_data &z_data, const rs2_intrinsics_double &intrin, double depth_units)
Definition: optimizer.cpp:1379
std::pair< double, p_matrix > calc_cost_and_grad(const z_frame_data &z_data, const std::vector< double3 > &new_vertices, const yuy2_frame_data &yuy_data, const calib &cal, const p_matrix &p_mat, data_collect *data=nullptr)
Definition: optimizer.cpp:1514
calib decompose(p_matrix const &mat, calib const &)
rs2_intrinsics intrin
std::vector< direction > get_direction(std::vector< double > gradient_x, std::vector< double > gradient_y)
Definition: optimizer.cpp:1110
GLfloat angle
Definition: glext.h:6819
GLint GLint GLsizei GLsizei GLsizei depth
float coeffs[5]
Definition: rs_types.h:67
GLdouble GLdouble GLdouble w
GLsizei const GLchar *const * string
d
Definition: rmse.py:171
void set_cycle_data(const std::vector< double3 > &vertices, const rs2_intrinsics_double &k_depth, const p_matrix &p_mat, const algo_calibration_registers &dsm_regs_cand, const rs2_dsm_params_double &dsm_params_cand)
Definition: optimizer.cpp:1837
GLdouble GLdouble z
unsigned char uint8_t
Definition: stdint.h:78
e
Definition: rmse.py:177
void write_obj(std::fstream &f, T const &o)
Definition: optimizer.cpp:1647
point
Definition: rmse.py:166
unsigned char temp_x2
Definition: rs_types.h:85
direction
Definition: rs-align.cpp:25
std::vector< byte > get_luminance_from_yuy2(std::vector< yuy_t > const &yuy2_imagh)
Definition: optimizer.cpp:1277
optimizer(settings const &, bool debug_mode=false)
Definition: optimizer.cpp:132
float rotation[9]
Definition: rs_sensor.h:98
GLenum GLenum GLsizei void * image
void write_matlab_camera_params_file(rs2_intrinsics const &_intr_depth, calib const &rgb_calibration, float _depth_units, std::string const &dir, char const *filename)
Definition: optimizer.cpp:1652
GLdouble t
void sample_by_mask(std::vector< T > &filtered, std::vector< T > const &origin, std::vector< byte > const &valid_edge_by_ir, size_t const width, size_t const height)
Definition: optimizer.cpp:258
GLuint GLfloat * val
size_t optimize(std::function< void(data_collect const &data) > iteration_callback=nullptr)
Definition: optimizer.cpp:1977
void clip_ac_scaling(rs2_dsm_params_double const &ac_data_orig, rs2_dsm_params_double &ac_data_new) const
void write_vector_to_file(std::vector< T > const &v, std::string const &dir, char const *filename)
Definition: utils.h:39
not_this_one begin(...)
GLdouble f
static std::pair< int, int > get_next_index(direction dir, int i, int j, size_t width, size_t height)
Definition: optimizer.cpp:209
GLsizeiptr size
void set_z_data(std::vector< z_t > &&z_data, rs2_intrinsics_double const &depth_intrinsics, rs2_dsm_params const &dms_params, algo_calibration_info const &cal_info, algo_calibration_registers const &cal_regs, float depth_units)
Definition: optimizer.cpp:455
GLdouble x
void sum_per_section(std::vector< double > &sum_weights_per_section, std::vector< byte > const &section_map, std::vector< double > const &weights, size_t num_of_sections)
Definition: optimizer.cpp:1302
GLdouble GLdouble x2
GLint GLsizei GLsizei height
void set_yuy_data(std::vector< yuy_t > &&yuy_data, std::vector< yuy_t > &&prev_yuy_data, std::vector< yuy_t > &&last_successful_yuy_data, calib const &calibration)
Definition: optimizer.cpp:991
GLint j
GLint left
Definition: glext.h:1963
std::vector< double > biliniar_interp(std::vector< double > const &vals, size_t width, size_t height, uvmap_t const &uv)
Definition: uvmap.cpp:76
void depth_filter(std::vector< T > &filtered, std::vector< T > const &origin, std::vector< byte > const &valid_edge_by_ir, size_t const width, size_t const height)
Definition: optimizer.cpp:276
rs2_intrinsics_double get_new_z_intrinsics_from_new_calib(const rs2_intrinsics_double &orig, const calib &new_c, const calib &orig_c)
Definition: optimizer.cpp:1100
static std::vector< double > sum_gradient_depth(std::vector< double > const &gradient, std::vector< double > const &direction_per_pixel)
Definition: optimizer.cpp:379
std::vector< uint8_t > is_suppressed(std::vector< double > const &local_edges, size_t valid_size)
Definition: optimizer.cpp:343
#define AC_LOG(TYPE, MSG)
float dot_product(const float(&a)[3], const float(&b)[3])
float3 transform(const rs2_extrinsics *extrin, const float3 &point)
Definition: pointcloud.cpp:47
Cross-stream extrinsics: encodes the topology describing how the different devices are oriented...
Definition: rs_sensor.h:96
static std::pair< int, int > get_prev_index(direction dir, int i, int j, size_t width, size_t height)
Definition: optimizer.cpp:182
double calc_cost_per_vertex_diff(z_frame_data const &z_data, yuy2_frame_data const &yuy_data, const uvmap_t &uvmap_old, const uvmap_t &uvmap_new)
Definition: cost.cpp:37
GLuint GLfloat GLfloat GLfloat x1
Definition: glext.h:9721
void set_ir_data(std::vector< ir_t > &&ir_data, size_t width, size_t height)
Definition: optimizer.cpp:1081
unsigned char byte
Definition: src/types.h:52
static const struct @18 vertices[3]
GLdouble right
static auto it
std::vector< byte > find_valid_depth_edges(std::vector< double > const &grad_in_direction, std::vector< byte > const &is_supressed, std::vector< double > const &values_for_subedges, std::vector< double > const &ir_local_edges, const params &p)
Definition: optimizer.cpp:399
static std::vector< double > get_direction_deg2(std::vector< double > const &gradient_x, std::vector< double > const &gradient_y)
Definition: optimizer.cpp:162
static p_matrix calc_p_gradients(const z_frame_data &z_data, const std::vector< double3 > &new_vertices, const yuy2_frame_data &yuy_data, std::vector< double > interp_IDT_x, std::vector< double > interp_IDT_y, const calib &cal, const p_matrix &p_mat, const std::vector< double > &rc, const std::vector< double2 > &xy, data_collect *data=nullptr)
Definition: optimizer.cpp:1387
uvmap_t get_texture_map(std::vector< double3 > const &points, const calib &cal, const p_matrix &p_mat)
Definition: uvmap.cpp:52
int min(int a, int b)
Definition: lz4s.c:73
const GLuint GLenum const void * binary
Definition: glext.h:1882
double calc_cost(const z_frame_data &z_data, const yuy2_frame_data &yuy_data, const std::vector< double2 > &uv, std::vector< double > *p_interpolated_edges)
Definition: cost.cpp:75
coeffs< p_matrix > calc_p_coefs(const z_frame_data &z_data, const std::vector< double3 > &new_vertices, const yuy2_frame_data &yuy_data, const calib &cal, const p_matrix &p_mat, const std::vector< double > &rc, const std::vector< double2 > &xy)
Definition: coeffs.cpp:695
struct librealsense::algo::depth_to_rgb_calibration::yuy2_frame_data::@0 debug
void zero_margin(std::vector< double > &gradient, size_t margin, size_t width, size_t height)
Definition: optimizer.cpp:237
typename::boost::move_detail::remove_reference< T >::type && move(T &&t) BOOST_NOEXCEPT
Video stream intrinsics.
Definition: rs_types.h:58
void deproject_sub_pixel(std::vector< double3 > &points, const rs2_intrinsics_double &intrin, std::vector< byte > const &valid_edges, const double *x, const double *y, const double *depth, double depth_units)
Definition: optimizer.cpp:1357
void grid_xy(std::vector< double > &gridx, std::vector< double > &gridy, size_t width, size_t height)
Definition: optimizer.cpp:296
rs2_digital_gain
digital gain for RS2_OPTION_DIGITAL_GAIN option.
Definition: rs_option.h:183
int i
GLuint res
Definition: glext.h:8856
#define INFO(msg)
Definition: catch.hpp:17429
std::vector< uint8_t > get_logic_edges(std::vector< double > const &edges)
Definition: optimizer.cpp:1287
std::vector< double > blur_edges(std::vector< double > const &edges, size_t image_width, size_t image_height)
Definition: optimizer.cpp:1233
std::vector< direction > get_direction2(std::vector< double > gradient_x, std::vector< double > gradient_y)
Definition: optimizer.cpp:1131
optimization_params back_tracking_line_search(optimization_params const &opt_params, const std::vector< double3 > &new_vertices, data_collect *data=nullptr) const
Definition: optimizer.cpp:1756
static std::pair< std::vector< double2 >, std::vector< double > > calc_rc(const z_frame_data &z_data, const std::vector< double3 > &new_vertices, const yuy2_frame_data &yuy_data, const calib &cal, const p_matrix &p_mat)
Definition: optimizer.cpp:1431
void section_per_pixel(frame_data const &, size_t section_w, size_t section_h, byte *section_map)
GLboolean * data
void pinv_3x3(const double in[9], double out[9])
Definition: pinv_3x3.cpp:828
GLdouble v
GLdouble y1
static void project_point_to_pixel(double pixel[2], const struct rs2_intrinsics_double *intrin, const double point[3])
Definition: optimizer.cpp:1210
Definition: parser.hpp:150
GLint GLsizei width
GLdouble GLdouble GLint GLint const GLdouble * points
void copy(void *dst, void const *src, size_t size)
Definition: types.cpp:836
void write_data_to(std::string const &directory)
Definition: optimizer.cpp:1715
std::string to_string(T value)


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:38