valid-scene.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 "debug.h"
11 #include <math.h>
12 #include <numeric>
13 
14 #define GAUSS_CONV_ROWS 4
15 #define GAUSS_CONV_COLUMNS 4
16 #define GAUSS_CONV_CORNERS 16
17 
20 
21 
22 template<class T>
23 std::vector<double> gauss_convolution(std::vector<T> const& image,
24  size_t image_width, size_t image_height,
25  size_t mask_width, size_t mask_height,
26  std::function< double(std::vector<T> const& sub_image) > convolution_operation
27  )
28 {
29  // boundaries handling
30  // Extend - The nearest border pixels are conceptually extended as far as necessary to provide values for the convolution.
31  // Corner pixels are extended in 90° wedges.Other edge pixels are extended in lines.
32  // https://en.wikipedia.org/wiki/Kernel_(image_processing)
33  // handling order:
34  // 1. rows: 0,1 and image_height-1, image_height-2
35  // 2. columns: 0,1 and image_width-1, image_width-2
36  // 3. corners: 4 pixels in each corner
37  // 4. rest of the pixels
38 
39  // 1. rows handling :
40  std::vector<double> res(image.size(), 0);
41  std::vector<T> sub_image(mask_width * mask_height, 0);
42  size_t ind = 0;
43  size_t row_bound[GAUSS_CONV_ROWS] = { 0, 1, image_height - 1,image_height - 2 };
44  size_t lines[GAUSS_CONV_ROWS] = { 2, 1, 2 , 1 };
45  size_t first_rows[GAUSS_CONV_ROWS] = { 1,1,0,0 };
46  size_t last_rows[GAUSS_CONV_ROWS] = { 0,0,1,1 };
47 
48  for (auto row = 0; row < GAUSS_CONV_ROWS; row++) {
49  for (auto jj = 0; jj < image_width - mask_width + 1; jj++)
50  {
51  ind = first_rows[row] * mask_width * lines[row]; // skip first 1/2 rows in sub-image for padding - start from 2nd/3rd line
52  for (auto l = first_rows[row] * lines[row]; l < mask_height - last_rows[row] * lines[row]; l++)
53  {
54  for (size_t k = 0; k < mask_width; k++)
55  {
56  auto p = (l - first_rows[row] * lines[row] + last_rows[row] * (-2 + row_bound[row])) * image_width + jj + k;
57  sub_image[ind++] = (image[p]);
58  }
59  }
60  // fill first 2 lines to same values as 3rd line
61  ind = first_rows[row] * mask_width * lines[row] + last_rows[row] * (mask_width * (mask_height - lines[row]));
62  auto ind_pad = last_rows[row] * (mask_width * (mask_height - lines[row] - 1)); // previous line
63  for (size_t k = 0; k < mask_width * lines[row]; k++)
64  {
65  auto idx1 = last_rows[row] * ind;
66  auto idx2 = last_rows[row] * ind_pad + first_rows[row] * ind;
67  sub_image[k + idx1] = sub_image[k % mask_width + idx2];
68  }
69  auto mid = jj + mask_width / 2 + row_bound[row] * image_width;
70  res[mid] = convolution_operation(sub_image);
71  }
72  }
73 
74  // 2. columns handling :
75  size_t column_boundaries[GAUSS_CONV_COLUMNS] = { 0,1, image_width - 1 ,image_width - 2 };
76  size_t columns[GAUSS_CONV_COLUMNS] = { 2, 1, 2, 1 };
77  size_t left_column[GAUSS_CONV_COLUMNS] = { 1,1,0,0 };
78  size_t right_column[GAUSS_CONV_COLUMNS] = { 0,0,1,1 };
79  for (auto col = 0; col < GAUSS_CONV_COLUMNS; col++) {
80  for (size_t ii = 0; ii < image_height - mask_height + 1; ii++)
81  {
82  ind = 0;
83  for (size_t l = 0; l < mask_height; l++)
84  {
85  ind += left_column[col] * columns[col];
86  for (auto k = left_column[col] * columns[col]; k < mask_width - right_column[col] * columns[col]; k++)
87  {
88  size_t p = (ii + l) * image_width + k - left_column[col] * columns[col] + right_column[col] * (column_boundaries[col] - 2);
89  sub_image[ind++] = (image[p]);
90  }
91  ind += right_column[col] * columns[col];
92  }
93  // fill first 2 columns to same values as 3rd column
94  ind = columns[col];
95  for (size_t l = 0; l < mask_height; l++)
96  {
97  ind = left_column[col] * columns[col] + right_column[col] * (mask_height - columns[col] - 1) + l * mask_width;
98  for (size_t k = 1; k <= columns[col]; k++)
99  {
100  auto idx = left_column[col] * (ind - k) + right_column[col] * (ind + k);
101  sub_image[idx] = sub_image[ind];
102  }
103  }
104  auto mid = (ii + mask_height / 2) * image_width + column_boundaries[col];
105  res[mid] = convolution_operation(sub_image);
106  }
107  }
108 
109  // 3. corners handling
110  size_t corners_arr[GAUSS_CONV_CORNERS] = { 0,1,image_width, image_width + 1, image_width - 1, image_width - 2, 2 * image_width - 1, 2 * image_width - 2,
111  (image_height - 2) * image_width,(image_height - 2) * image_width, // left corners - line before the last
112  (image_height - 1) * image_width,(image_height - 1) * image_width,
113  (image_height - 2) * image_width,(image_height - 2) * image_width, // right corners - last row
114  (image_height - 1) * image_width,(image_height - 1) * image_width };
115 
116  size_t corners_arr_col[GAUSS_CONV_CORNERS] = { 0,0,0,0,0,0,0,0,0,1,0,1,image_width - 1,image_width - 2,image_width - 1,image_width - 2 };
117  size_t left_col[GAUSS_CONV_CORNERS] = { 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0 };
118  size_t right_col[GAUSS_CONV_CORNERS] = { 0,0,0,0,1,1 ,1,1,0,0,0,0,1,1,1,1 };
119  size_t up_rows[GAUSS_CONV_CORNERS] = { 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 };
120  size_t down_rows[GAUSS_CONV_CORNERS] = { 0,0,0,0,0,0 ,0,0,1,1,1,1,1,1,1,1 };
121  size_t corner_columns[GAUSS_CONV_CORNERS] = { 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1 };
122  size_t corner_rows[GAUSS_CONV_CORNERS] = { 2, 2,1,1 ,2,2,1,1,1,1,2,2,1,1,2,2 };
123  for (auto corner = 0; corner < GAUSS_CONV_CORNERS; corner++) {
124  ind = up_rows[corner] * corner_rows[corner] * mask_width; // starting point in sub-image
125  for (auto l = up_rows[corner] * corner_rows[corner]; l < mask_height - down_rows[corner] * corner_rows[corner]; l++)
126  {
127  ind += left_col[corner] * corner_columns[corner];
128  for (auto k = left_col[corner] * corner_columns[corner]; k < mask_width - right_col[corner] * corner_columns[corner]; k++)
129  {
130  auto up_row_i = (l - corner_rows[corner] + right_col[corner] * (corner_rows[corner] - 2)) * image_width;
131  auto up_col_i = k - left_col[corner] * corner_columns[corner] + right_col[corner] * (corners_arr[corner] - 2);
132  auto down_row_i = (l - 2) * image_width + corners_arr[corner];
133  auto down_col_i = k - left_col[corner] * corner_columns[corner] + right_col[corner] * (corners_arr_col[corner] - 2);
134  auto col_i = down_rows[corner] * down_col_i + up_rows[corner] * up_col_i;
135  auto row_i = down_rows[corner] * down_row_i + up_rows[corner] * up_row_i;
136  auto p = row_i + col_i;
137  sub_image[ind++] = (image[p]);
138  }
139  ind += right_col[corner] * corner_columns[corner];
140  }
141  // fill first 2 columns to same values as 3rd column
142  // and first 2 rows to same values as 3rd row
143  // 3.1. rows
144  auto l_init = down_rows[corner] * (mask_height - corner_rows[corner]); // pad last rows
145  auto l_limit = up_rows[corner] * corner_rows[corner] + down_rows[corner] * mask_height;
146  for (auto l = l_init; l < l_limit; l++)
147  {
148  ind = up_rows[corner] * (corner_rows[corner] * mask_width) + down_rows[corner] * (mask_height - corner_rows[corner] - 1) * mask_width; // start with padding first 2 rows
149  auto ind2 = l * mask_width;
150  for (size_t k = 0; k < mask_width; k++)
151  {
152  sub_image[k + ind2] = sub_image[ind++];
153  }
154  }
155  // 3.2. columns
156  for (size_t l = 0; l < mask_height; l++)
157  {
158  ind = l * mask_width + left_col[corner] * corner_columns[corner] + right_col[corner] * (mask_width - 1 - corner_columns[corner]);
159  auto ind2 = l * mask_width + right_col[corner] * (mask_width - corner_columns[corner]);
160  for (size_t k = 0; k < corner_columns[corner]; k++)
161  {
162  sub_image[k + ind2] = sub_image[ind];
163  }
164  }
165  auto mid = corners_arr[corner] + corners_arr_col[corner];
166  res[mid] = convolution_operation(sub_image);
167  }
168 
169  // 4. rest of the pixel in the middle
170  for (size_t i = 0; i < image_height - mask_height + 1; i++)
171  {
172  for (size_t j = 0; j < image_width - mask_width + 1; j++)
173  {
174  ind = 0;
175  for (size_t l = 0; l < mask_height; l++)
176  {
177  for (size_t k = 0; k < mask_width; k++)
178  {
179  size_t p = (i + l) * image_width + j + k;
180  sub_image[ind++] = (image[p]);
181  }
182 
183  }
184  auto mid = (i + mask_height / 2) * image_width + j + mask_width / 2;
185  res[mid] = convolution_operation(sub_image);
186  }
187  }
188  return res;
189 }
190 
191 
192 template<class T>
193 std::vector<uint8_t> dilation_convolution(std::vector<T> const& image,
194  size_t image_width, size_t image_height,
195  size_t mask_width, size_t mask_height,
196  std::function< uint8_t(std::vector<T> const& sub_image) > convolution_operation
197  )
198 {
199  // poundaries handling
200  // Extend boundary rows and columns to zeros
201 
202  // 1. rows
203  std::vector<uint8_t> res(image.size(), 0);
204  std::vector<T> sub_image(mask_width * mask_height, 0);
205  auto ind = 0;
206  size_t rows[2] = { 0, image_height - 1 };
207 
208  for (auto rows_i = 0; rows_i < 2; rows_i++) {
209  for (auto jj = 0; jj < image_width - mask_width + 1; jj++)
210  {
211  ind = 0;
212  for (size_t l = 0; l < mask_height; l++)
213  {
214  for (size_t k = 0; k < mask_width; k++)
215  {
216  size_t p = (l + rows[rows_i]) * image_width + jj + k;
217  if (rows_i != 0)
218  {
219  p = p - 2 * image_width;
220  }
221  sub_image[ind] = (image[p]);
222  bool cond1 = (l == 2) && (rows_i == 0);
223  bool cond2 = (l == 0) && (rows_i == 1);
224  if (cond1 || cond2) {
225  sub_image[ind] = 0;
226  }
227  ind++;
228  }
229  }
230  size_t mid = jj + mask_width / 2 + rows[rows_i] * image_width;
231  res[mid] = convolution_operation(sub_image);
232  }
233  }
234 
235  // 2. columns
236  size_t columns[2] = { 0, image_width - 1 };
237  for (size_t columns_i = 0; columns_i < 2; columns_i++) {
238  for (size_t ii = 0; ii < image_height - mask_height + 1; ii++)
239  {
240  ind = 0;
241  for (size_t l = 0; l < mask_height; l++)
242  {
243  for (size_t k = 0; k < mask_width; k++)
244  {
245  size_t p = (ii + l) * image_width + k + columns[columns_i];
246  if (columns_i != 0)
247  {
248  p = p - 2;
249  }
250  sub_image[ind] = (image[p]);
251  bool cond1 = (k == 2) && (columns_i == 0);
252  bool cond2 = (k == 0) && (columns_i == 1);
253  if (cond1 || cond2) {
254  sub_image[ind] = 0;
255  }
256  ind++;
257  }
258  auto mid = (ii + mask_height / 2) * image_width + columns[columns_i];
259  res[mid] = convolution_operation(sub_image);
260  }
261  }
262  }
263  // 3. rest of the pixels
264  for (size_t i = 0; i < image_height - mask_height + 1; i++)
265  {
266  for (size_t j = 0; j < image_width - mask_width + 1; j++)
267  {
268  ind = 0;
269  for (size_t l = 0; l < mask_height; l++)
270  {
271  for (size_t k = 0; k < mask_width; k++)
272  {
273  size_t p = (i + l) * image_width + j + k;
274  sub_image[ind++] = (image[p]);
275  }
276 
277  }
278  size_t mid = (i + mask_height / 2) * image_width + j + mask_width / 2;
279  res[mid] = convolution_operation(sub_image);
280  }
281  }
282  return res;
283 }
284 
285 
286 static bool check_edge_distribution( std::vector< double > & sum_weights_per_section,
287  double const min_min_max_ratio,
288  double const min_weighted_edge_per_section,
289  double & min_max_ratio )
290 {
291  /*minMaxRatio = min(sumWeightsPerSection)/max(sumWeightsPerSection);
292  if minMaxRatio < params.edgeDistributMinMaxRatio
293  isDistributed = false;
294  fprintf('isEdgeDistributed: Ratio between min and max is too small: %0.5f, threshold is %0.5f\n',minMaxRatio, params.edgeDistributMinMaxRatio);
295  return;
296  end*/
297 
298  double z_max = *std::max_element(sum_weights_per_section.begin(), sum_weights_per_section.end());
299  double z_min = *std::min_element(sum_weights_per_section.begin(), sum_weights_per_section.end());
300  min_max_ratio = z_min / z_max;
301  if( min_max_ratio < min_min_max_ratio )
302  {
303  AC_LOG( DEBUG,
304  "Edge distribution ratio ({min}"
305  << z_min << "/" << z_max << "{max} = " << min_max_ratio
306  << ") is too small; minimum= " << min_min_max_ratio );
307  return false;
308  }
309 
310  /*if any(sumWeightsPerSection< params.minWeightedEdgePerSection)
311  isDistributed = false;
312  printVals = num2str(sumWeightsPerSection(1));
313  for k = 2:numel(sumWeightsPerSection)
314  printVals = [printVals,',',num2str(sumWeightsPerSection(k))];
315  end
316  disp(['isEdgeDistributed: weighted edge per section is too low: ' printVals ', threshold is ' num2str(params.minWeightedEdgePerSection)]);
317  return;
318 end*/
319  bool is_edge_distributed = true;
320  for( auto it = sum_weights_per_section.begin(); it != sum_weights_per_section.end(); ++it )
321  {
322  if( *it < min_weighted_edge_per_section )
323  {
324  is_edge_distributed = false;
325  break;
326  }
327  }
328  if( ! is_edge_distributed )
329  {
330  AC_LOG( DEBUG, "check_edge_distribution: weighted edge per section is too low: " );
331  for( auto it = sum_weights_per_section.begin(); it != sum_weights_per_section.end(); ++it )
332  AC_LOG( DEBUG, " " << *it );
333  AC_LOG( DEBUG, "threshold is: " << min_weighted_edge_per_section );
334  }
335  return is_edge_distributed;
336 }
337 
338 
340 {
342 
343  // depth frame
344  AC_LOG(DEBUG, " checking Z edge distribution");
346  //for debug
347  auto it = z.sum_weights_per_section.begin();
348  AC_LOG(DEBUG, " sum_per_section(z), section #0 " << *(it));
349  AC_LOG(DEBUG, " sum_per_section(z), section #1 " << *(it + 2));
350  AC_LOG(DEBUG, " sum_per_section(z), section #2 " << *(it + 1));
351  AC_LOG(DEBUG, " sum_per_section(z), section #3 " << *(it + 3));
355  z.min_max_ratio );
356 
357  // yuy frame
358  AC_LOG(DEBUG, " checking YUY edge distribution");
359 
360  // Get a map for each pixel to its corresponding section
361  std::vector< byte > section_map_rgb( _yuy.width * _yuy.height );
363  _params.num_of_sections_for_edge_distribution_x, //% params.numSectionsH
364  _params.num_of_sections_for_edge_distribution_y, //% params.numSectionsV
365  section_map_rgb.data() );
366 
367  sum_per_section( yuy.sum_weights_per_section, section_map_rgb, yuy.edges_IDT, num_of_sections );
368  //for debug
369  it = yuy.sum_weights_per_section.begin();
370  AC_LOG(DEBUG, " sum_per_section(yuy), section #0 " << *(it));
371  AC_LOG(DEBUG, " sum_per_section(yuy), section #1 " << *(it + 2));
372  AC_LOG(DEBUG, " sum_per_section(yuy), section #2 " << *(it + 1));
373  AC_LOG(DEBUG, " sum_per_section(yuy), section #3 " << *(it + 3));
377  yuy.min_max_ratio );
378 
379  return (z.is_edge_distributed && yuy.is_edge_distributed);
380 }
381 
382 //%function[isBalanced, dirRatio1, perpRatio, dirRatio2, weightsPerDir] = isGradDirBalanced( frame, params )
383 static bool is_grad_dir_balanced( std::vector< double > const & weights,
384  std::vector< double > const & directions,
385  params const & _params,
386  std::vector< double > * p_weights_per_dir,
387  double * p_dir_ratio1 )
388 {
389  //%weightsPerDir = sum( frame.weights .* (frame.dirPerPixel == [1:4]) );
390  std::vector< double > weights_per_dir( 4, 0. ); // 4 = deg_non is number of directions
391  for (auto dir = 0; dir < 4; ++dir)
392  {
393  for(size_t ii = 0; ii < directions.size(); ++ii )
394  {
395  if( directions[ii] == dir + 1 ) // avoid direction 0
396  weights_per_dir[dir] += weights[ii];
397  }
398  }
399  if( p_weights_per_dir )
400  *p_weights_per_dir = weights_per_dir;
401 
402  /*
403  [maxVal,maxIx] = max(weightsPerDir);
404  ixMatch = mod(maxIx+2,4);
405  if ixMatch == 0
406  ixMatch = 4;
407  end
408  if weightsPerDir(ixMatch) < 1e-3 %Don't devide by zero...
409  dirRatio1 = 1e6;
410  else
411  dirRatio1 = maxVal/weightsPerDir(ixMatch);
412  end
413  */
414  //%[maxVal, maxIx] = max( weightsPerDir );
415  auto max_val = max_element( weights_per_dir.begin(), weights_per_dir.end() );
416  auto max_ix = distance( weights_per_dir.begin(), max_val );
417  //%ixMatch = mod( maxIx + 2, 4 );
418  //%if ixMatch == 0
419  //% ixMatch = 4;
420  //%end
421  auto ix_match = (max_ix + 1) % 3;
422 
423  double dir_ratio1;
424  //%if weightsPerDir( ixMatch ) < 1e-3 %Don't devide by zero...
425  if (weights_per_dir.at(ix_match) < 1e-3) //%Don't devide by zero...
426  dir_ratio1 = 1e6;
427  else
428  //%dirRatio1 = maxVal / weightsPerDir( ixMatch );
429  dir_ratio1 = *max_val / weights_per_dir.at( ix_match );
430  if( p_dir_ratio1 )
431  *p_dir_ratio1 = dir_ratio1;
432 
433  //%if dirRatio1 > params.gradDirRatio
434  if( dir_ratio1 > _params.grad_dir_ratio )
435  {
436  //%ixCheck = true(size(weightsPerDir));
437  //%ixCheck([maxIx,ixMatch]) = false;
438  //%[maxValPerp,~] = max(weightsPerDir(ixCheck));
439  double max_val_perp = DBL_MIN;
440  double min_val_perp = DBL_MAX;
441  for (auto i = 0; i < 4; ++i)
442  {
443  if ((i != max_ix) && (i != ix_match))
444  {
445  if( max_val_perp < weights_per_dir[i] )
446  max_val_perp = weights_per_dir[i];
447  if( min_val_perp > weights_per_dir[i] )
448  min_val_perp = weights_per_dir[i];
449  }
450  }
451 
452  //%perpRatio = maxVal/maxValPerp;
453  auto perp_ratio = *max_val / max_val_perp;
454  if( perp_ratio > _params.grad_dir_ratio_prep )
455  {
456  AC_LOG( DEBUG,
457  " gradient direction is not balanced : " << dir_ratio1 << "; threshold is: "
458  << _params.grad_dir_ratio );
459  return false;
460  }
461  if( min_val_perp < 1e-3 ) // % Don't devide by zero...
462  {
463  AC_LOG( DEBUG,
464  " gradient direction is not balanced : " << dir_ratio1 << "; threshold is: "
465  << _params.grad_dir_ratio );
466  return false;
467  }
468 
469  //%dirRatio2 = maxValPerp / min( weightsPerDir( ixCheck ));
470  double dir_ratio2 = max_val_perp / min_val_perp;
471  //%if dirRatio2 > params.gradDirRatio
472  if( dir_ratio2 > _params.grad_dir_ratio )
473  {
474  AC_LOG( DEBUG,
475  " gradient direction is not balanced : " << dir_ratio1 << "; threshold is: "
476  << _params.grad_dir_ratio );
477  return false;
478  }
479  }
480  return true;
481 }
482 
483 
485  size_t const section_w,
486  size_t const section_h,
487  byte * const section_map )
488 {
489  //% [gridX,gridY] = meshgrid(0:res(2)-1,0:res(1)-1);
490  //% gridX = floor(gridX/res(2)*params.numSectionsH);
491  //% gridY = floor(gridY/res(1)*params.numSectionsV);
492 
493  // res(2) is width; res(1) is height
494  // --> section_x = x * section_w / width
495  // --> section_y = y * section_h / height
496 
497  // We need to align the pixel-map orientation the same as the image data
498  // In Matlab, it's always height-oriented (data + x*h + y) whereas our frame
499  // data is width-oriented (data + y*w + x)
500  // --> we iterate over cols within rows
501 
502  assert(section_w * section_h <= 256);
503 
504  byte* section = section_map;
505  for (size_t row = 0; row < f.height; row++)
506  {
507  size_t const section_y = row * section_h / f.height; // note not a floating point division!
508  for (size_t col = 0; col < f.width; col++)
509  {
510  size_t const section_x = col * section_w / f.width; // note not a floating point division!
511  //% sectionMap = gridY + gridX*params.numSectionsH; TODO BUGBUGBUG!!!
512  *section++ = byte(section_y + section_x * section_h);
513  }
514  }
515 }
516 
517 
518 template<class T>
519 uint8_t dilation_calc(std::vector<T> const& sub_image, std::vector<uint8_t> const& mask)
520 {
521  uint8_t res = 0;
522 
523  for (size_t i = 0; i < sub_image.size(); i++)
524  {
525  res = res || (uint8_t)(sub_image[i] * mask[i]);
526  }
527 
528  return res;
529 }
530 
531 
532 std::vector< uint8_t > optimizer::images_dilation( std::vector< uint8_t > const & logic_edges,
533  size_t width,
534  size_t height )
535 {
536  if( _params.dilation_size == 1 )
537  return logic_edges;
538 
539  std::vector< uint8_t > dilation_mask = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
540  return dilation_convolution< uint8_t >( logic_edges,
541  width,
542  height,
545  [&]( std::vector< uint8_t > const & sub_image ) {
546  return dilation_calc( sub_image, dilation_mask );
547  } );
548 }
549 
550 
551 template<class T>
552 double gaussian_calc(std::vector<T> const& sub_image, std::vector<double> const& mask)
553 {
554  double res = 0;
555 
556  for (auto i = 0; i < sub_image.size(); i++)
557  {
558  res = res + (double)(sub_image[i] * mask[i]);
559  }
560 
561  return res;
562 }
563 
564 
565 void optimizer::gaussian_filter( std::vector< uint8_t > const & lum_frame,
566  std::vector< uint8_t > const & prev_lum_frame,
567  std::vector< double > & yuy_diff,
568  std::vector< double > & gaussian_filtered_image,
569  size_t width,
570  size_t height )
571 {
572 
573  auto area = height *width;
574 
575  /* diffIm = abs(im1-im2);
576 diffIm = imgaussfilt(im1-im2,params.moveGaussSigma);*/
577  // use this matlab function to get gauss kernel with sigma=1: disp17(fspecial('gaussian',5,1))
578  std::vector< double > gaussian_kernel
579  = { 0.0029690167439504968, 0.013306209891013651, 0.021938231279714643, 0.013306209891013651,
580  0.0029690167439504968, 0.013306209891013651, 0.059634295436180138, 0.098320331348845769,
581  0.059634295436180138, 0.013306209891013651, 0.021938231279714643, 0.098320331348845769,
582  0.16210282163712664, 0.098320331348845769, 0.021938231279714643, 0.013306209891013651,
583  0.059634295436180138, 0.098320331348845769, 0.059634295436180138, 0.013306209891013651,
584  0.0029690167439504968, 0.013306209891013651, 0.021938231279714643, 0.013306209891013651,
585  0.0029690167439504968 };
586 
587  auto yuy_iter = lum_frame.begin();
588  auto yuy_prev_iter = prev_lum_frame.begin();
589  for (auto i = 0UL; i < area; i++, yuy_iter++, yuy_prev_iter++)
590  {
591  yuy_diff.push_back((double)(*yuy_prev_iter) - (double)(*yuy_iter)); // used for testing only
592  }
593  gaussian_filtered_image
594  = gauss_convolution< double >( yuy_diff,
595  width,
596  height,
599  [&]( std::vector< double > const & sub_image ) {
600  return gaussian_calc( sub_image, gaussian_kernel );
601  } );
602 }
603 
604 
605 static void abs_values( std::vector< double > & vec_in )
606 {
607  for( double & val : vec_in )
608  {
609  if (val < 0)
610  val *= -1;
611  }
612 }
613 
614 
615 static void gaussian_dilation_mask( std::vector< double > & gauss_diff,
616  std::vector< uint8_t > const & dilation_mask )
617 {
618  auto gauss_it = gauss_diff.begin();
619  auto dilation_it = dilation_mask.begin();
620  for(size_t i = 0; i < gauss_diff.size(); i++, gauss_it++, dilation_it++ )
621  {
622  if( *dilation_it )
623  *gauss_it = 0;
624  }
625 }
626 
627 
628 static size_t move_suspected_mask( std::vector< uint8_t > & move_suspect,
629  std::vector< double > const & gauss_diff_masked,
630  double const movement_threshold )
631 {
632  move_suspect.reserve( gauss_diff_masked.size() );
633  size_t n_movements = 0;
634  for( auto it = gauss_diff_masked.begin(); it != gauss_diff_masked.end(); ++it )
635  {
636  if( *it > movement_threshold )
637  {
638  move_suspect.push_back(1);
639  ++n_movements;
640  }
641  else
642  {
643  move_suspect.push_back(0);
644  }
645  }
646  return n_movements;
647 }
648 
649 
651  movement_inputs_for_frame const & curr,
652  movement_result_data * const result_data,
653  double const move_thresh_pix_val,
654  double const move_threshold_pix_num,
655  size_t const width,
656  size_t const height )
657 {
658 
659  /*function [isMovement,movingPixels] = isMovementInImages(im1,im2, params)
660 isMovement = false;
661 
662 [edgeIm1,~,~] = OnlineCalibration.aux.edgeSobelXY(uint8(im1));
663 logicEdges = abs(edgeIm1) > params.edgeThresh4logicIm*max(edgeIm1(:));
664 SE = strel('square', params.seSize);
665 dilatedIm = imdilate(logicEdges,SE);
666 diffIm = imgaussfilt(double(im1)-double(im2),params.moveGaussSigma);
667 */
668  std::vector< double > gaussian_diff_masked;
669  {
670  std::vector< uint8_t > dilated_image;
671  {
672  std::vector< double > gaussian_filtered_image;
673  {
674  auto logic_edges = get_logic_edges( prev.edges );
675  dilated_image = images_dilation( logic_edges, width, height );
676  std::vector< double > yuy_diff;
678  curr.lum_frame,
679  yuy_diff,
680  gaussian_filtered_image,
681  width,
682  height );
683  if( result_data )
684  {
685  result_data->logic_edges = std::move( logic_edges );
686  result_data->yuy_diff = std::move( yuy_diff );
687  }
688  }
689  /*
690  %
691  IDiffMasked = abs(diffIm);
692  IDiffMasked(dilatedIm) = 0;
693  % figure; imagesc(IDiffMasked); title('IDiffMasked');impixelinfo; colorbar;
694  ixMoveSuspect = IDiffMasked > params.moveThreshPixVal;
695  if sum(ixMoveSuspect(:)) > params.moveThreshPixNum
696  isMovement = true;
697  end
698  movingPixels = sum(ixMoveSuspect(:));
699  disp(['isMovementInImages: # of pixels above threshold ' num2str(sum(ixMoveSuspect(:))) ',
700  allowed #: ' num2str(params.moveThreshPixNum)]); end*/
701  gaussian_diff_masked = gaussian_filtered_image;
702  if( result_data )
703  result_data->gaussian_filtered_image = std::move( gaussian_filtered_image );
704  }
705  abs_values( gaussian_diff_masked );
706  gaussian_dilation_mask( gaussian_diff_masked, dilated_image );
707  if( result_data )
708  result_data->dilated_image = std::move( dilated_image );
709  }
710 
711  std::vector< uint8_t > move_suspect;
712  auto sum_move_suspect
713  = move_suspected_mask( move_suspect, gaussian_diff_masked, move_thresh_pix_val );
714  if( result_data )
715  {
716  result_data->gaussian_diff_masked = std::move( gaussian_diff_masked );
717  result_data->move_suspect = std::move( move_suspect );
718  }
719 
720  if( sum_move_suspect > move_threshold_pix_num )
721  {
722  AC_LOG( DEBUG,
723  " found movement: " << sum_move_suspect << " pixels above threshold; allowed: "
725  return true;
726  }
727 
728  return false;
729 }
730 
731 
733 {
734  std::vector< byte > section_map_depth( _z.width * _z.height );
735 
736  size_t const section_w = _params.num_of_sections_for_edge_distribution_x; //% params.numSectionsH
737  size_t const section_h = _params.num_of_sections_for_edge_distribution_y; //% params.numSectionsH
738 
739  // Get a map for each pixel to its corresponding section
740  section_per_pixel( _z, section_w, section_h, section_map_depth.data() );
741 
742  // remove pixels in section map that were removed in weights
743  AC_LOG( DEBUG, " " << _z.supressed_edges.size() << " total edges" );
744  AC_LOG( DEBUG, " " << _z.section_map.size() << " not suppressed" );
745 
746  // The previous and current frames must have "NO" movement between them
748  AC_LOG( ERROR, "Scene is not valid: movement detected between current & previous frames [MOVE]" );
749 
750  // These two are used in the results validity, in the decision params
751  bool res_edges = is_edge_distributed( _z, _yuy );
752  bool res_gradient = is_grad_dir_balanced( _z.weights,
753  _z.directions,
754  _params,
756  &_z.dir_ratio1 );
757 
759  valid = input_validity_checks(data) && valid;
760 
761  return(valid);
762 }
763 
764 bool check_edges_dir_spread(const std::vector<double>& directions,
765  const std::vector<double>& subpixels_x,
766  const std::vector<double>& subpixels_y,
767  size_t width,
768  size_t height,
769  const params& p)
770 {
771  // check if there are enough edges per direction
772  int edges_amount_per_dir[N_BASIC_DIRECTIONS] = { 0 };
773 
774  for (auto && i : directions)
775  {
776  edges_amount_per_dir[(int)i - 1]++;
777  }
778 
779  bool dirs_with_enough_edges[N_BASIC_DIRECTIONS] = { false };
780 
781  for (auto i = 0; i < N_BASIC_DIRECTIONS; i++)
782  {
783  auto edges_amount_per_dir_normalized = (double)edges_amount_per_dir[i] / (width * height);
784  dirs_with_enough_edges[i] = (edges_amount_per_dir_normalized > p.edges_per_direction_ratio_th);
785  }
786 
787  // std Check for valid directions
788  double2 dir_vecs[N_BASIC_DIRECTIONS] =
789  {
790  { 1, 0},
791  { 1 / sqrt(2), 1 / sqrt(2) },
792  { 0, 1 },
793  { -1 / sqrt(2), 1 / sqrt(2) }
794  };
795 
796 
797  auto diag_length = sqrt((double)width*(double)width + (double)height*(double)height);
798 
799  std::vector<double> val_per_dir[N_BASIC_DIRECTIONS];
800 
801  for (size_t i = 0; i < subpixels_x.size(); i++)
802  {
803  auto dir = (int)directions[i] - 1;
804  auto val = subpixels_x[i] * dir_vecs[dir].x + subpixels_y[i] * dir_vecs[dir].y;
805  val_per_dir[dir].push_back(val);
806  }
807 
808  double std_per_dir[N_BASIC_DIRECTIONS] = { 0 };
809  bool std_bigger_than_th[N_BASIC_DIRECTIONS] = { false };
810 
811  for (auto i = 0; i < N_BASIC_DIRECTIONS; i++)
812  {
813  auto curr_dir = val_per_dir[i];
814  double sum = std::accumulate(curr_dir.begin(), curr_dir.end(), 0.0);
815  double mean = sum / curr_dir.size();
816 
817  double dists_sum = 0;
818  std::for_each(curr_dir.begin(), curr_dir.end(), [&](double val) {dists_sum += (val - mean)*(val - mean); });
819 
820  // The denominator in the 'Sample standard deviation' formula is N − 1 vs 'Population standard deviation' that is N
821  // https://en.wikipedia.org/wiki/Standard_deviation
822  // we use 'Sample standard deviation' as Matlab
823  auto stdev = sqrt(dists_sum / (curr_dir.size() - 1));
824  std_per_dir[i] = stdev / diag_length;
825  std_bigger_than_th[i] = std_per_dir[i] > p.dir_std_th[i];
826  }
827 
828  bool valid_directions[N_BASIC_DIRECTIONS] = { false };
829 
830  for (auto i = 0; i < N_BASIC_DIRECTIONS; i++)
831  {
832  valid_directions[i] = dirs_with_enough_edges[i] && std_bigger_than_th[i];
833  }
834  auto valid_directions_sum = std::accumulate(&valid_directions[0], &valid_directions[N_BASIC_DIRECTIONS], 0);
835 
836  auto edges_dir_spread = valid_directions_sum >= p.minimal_full_directions;
837 
838  if (!edges_dir_spread)
839  {
840  AC_LOG( ERROR,
841  "Scene is not valid: not enough edge direction spread (have "
842  << valid_directions_sum << "; need " << p.minimal_full_directions << ") [EDGE-DIR]" );
843  return edges_dir_spread;
844  }
845 
847  {
848  auto valid_even = true;
849  for (auto i = 0; i < N_BASIC_DIRECTIONS; i += 2)
850  {
851  valid_even &= valid_directions[i];
852  }
853 
854  auto valid_odd = true;
855  for (auto i = 1; i < N_BASIC_DIRECTIONS; i += 2)
856  {
857  valid_odd &= valid_directions[i];
858  }
859  auto orthogonal_valid_dirs = valid_even || valid_odd;
860 
861  if( ! orthogonal_valid_dirs )
862  AC_LOG( ERROR,
863  "Scene is not valid: need at least two orthogonal directions that have enough "
864  "spread edges [EDGE-DIR]" );
865 
866  return edges_dir_spread && orthogonal_valid_dirs;
867  }
868 
869  return edges_dir_spread;
870 }
871 
872 bool check_saturation(const std::vector< ir_t >& ir_frame,
873  size_t width,
874  size_t height,
875  const params& p)
876 {
877  size_t saturated_pixels = 0;
878 
879  for (auto&& i : ir_frame)
880  {
881  if( i >= p.saturation_value )
882  saturated_pixels++;
883  }
884 
885  auto saturated_pixels_ratio = (double)saturated_pixels / (double)(width*height);
886 
887  if( saturated_pixels_ratio >= p.saturation_ratio_th )
888  AC_LOG( ERROR,
889  "Scene is not valid: saturation ratio ("
890  << saturated_pixels_ratio << ") is above threshold (" << p.saturation_ratio_th
891  << ") [SAT]" );
892 
893  return saturated_pixels_ratio < p.saturation_ratio_th;
894 }
895 
896 bool check_edges_spatial_spread(const std::vector<byte>& section_map,
897  size_t width,
898  size_t height,
899  double th,
900  size_t n_sections,
901  size_t min_section_with_enough_edges)
902 {
903  std::vector<int> num_pix_per_sec(n_sections, 0);
904 
905  for (auto&&i : section_map)
906  {
907  num_pix_per_sec[i]++;
908  }
909  std::vector<double> num_pix_per_sec_over_area(n_sections, 0);
910  std::vector<bool> num_sections_with_enough_edges(n_sections, false);
911 
912  for (size_t i = 0; i < n_sections; i++)
913  {
914  num_pix_per_sec_over_area[i] = (double)num_pix_per_sec[i] / (width*height)*n_sections;
915  num_sections_with_enough_edges[i] = num_pix_per_sec_over_area[i] > th;
916  }
917 
918  double sum = std::accumulate(num_sections_with_enough_edges.begin(), num_sections_with_enough_edges.end(), 0.0);
919 
920  return sum >= min_section_with_enough_edges;
921 }
922 
924 {
926  auto not_saturated = check_saturation(_ir.ir_frame, _ir.width, _ir.height, _params);
927 
928  auto depth_spatial_spread = check_edges_spatial_spread(
933 
934  auto rgb_spatial_spread = check_edges_spatial_spread(
936  _yuy.width, _yuy.height,
940 
941  if( ! depth_spatial_spread )
942  AC_LOG( ERROR, "Scene is not valid: not enough depth edge spread [EDGE-D]" );
943 
944  if( ! rgb_spatial_spread )
945  AC_LOG( ERROR, "Scene is not valid: not enough RGB edge spread [EDGE-C]" );
946 
948  AC_LOG( ERROR, "Scene is not valid: not enough movement from last-calibrated scene [SALC]" );
949 
950  if( data )
951  {
952  data->edges_dir_spread = dir_spread;
953  data->not_saturated = not_saturated;
954  data->depth_spatial_spread = depth_spatial_spread;
955  data->rgb_spatial_spread = rgb_spatial_spread;
957  }
958 
959  return dir_spread && not_saturated && depth_spatial_spread && rgb_spatial_spread
961 }
962 
963 
std::vector< uint8_t > images_dilation(std::vector< uint8_t > const &logic_edges, size_t width, size_t height)
std::vector< uint8_t > dilation_convolution(std::vector< T > const &image, size_t image_width, size_t image_height, size_t mask_width, size_t mask_height, std::function< uint8_t(std::vector< T > const &sub_image) > convolution_operation)
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)
const GLbyte * weights
Definition: glext.h:4709
static bool is_grad_dir_balanced(std::vector< double > const &weights, std::vector< double > const &directions, params const &_params, std::vector< double > *p_weights_per_dir, double *p_dir_ratio1)
GLenum GLenum GLsizei void * row
bool is_edge_distributed(z_frame_data &z_data, yuy2_frame_data &yuy_data)
GLfloat GLfloat p
Definition: glext.h:12687
bool input_validity_checks(input_validity_data *data=nullptr)
double gaussian_calc(std::vector< T > const &sub_image, std::vector< double > const &mask)
GLint GLuint mask
#define GAUSS_CONV_CORNERS
Definition: valid-scene.cpp:16
static bool check_edge_distribution(std::vector< double > &sum_weights_per_section, double const min_min_max_ratio, double const min_weighted_edge_per_section, double &min_max_ratio)
GLdouble GLdouble z
unsigned char uint8_t
Definition: stdint.h:78
e
Definition: rmse.py:177
GLsizei GLsizei GLfloat distance
Definition: glext.h:10563
bool check_edges_spatial_spread(const std::vector< byte > &section_map, size_t width, size_t height, double th, size_t n_sections, size_t min_section_with_enough_edges)
GLenum GLenum GLsizei void * image
GLuint GLfloat * val
static size_t move_suspected_mask(std::vector< uint8_t > &move_suspect, std::vector< double > const &gauss_diff_masked, double const movement_threshold)
static void gaussian_dilation_mask(std::vector< double > &gauss_diff, std::vector< uint8_t > const &dilation_mask)
GLdouble f
#define GAUSS_CONV_COLUMNS
Definition: valid-scene.cpp:15
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
GLint GLsizei GLsizei height
uint8_t dilation_calc(std::vector< T > const &sub_image, std::vector< uint8_t > const &mask)
GLint j
#define GAUSS_CONV_ROWS
Definition: valid-scene.cpp:14
bool check_edges_dir_spread(const std::vector< double > &directions, const std::vector< double > &subpixels_x, const std::vector< double > &subpixels_y, size_t width, size_t height, const params &p)
#define AC_LOG(TYPE, MSG)
bool check_saturation(const std::vector< ir_t > &ir_frame, size_t width, size_t height, const params &p)
static void abs_values(std::vector< double > &vec_in)
unsigned char byte
Definition: src/types.h:52
bool is_scene_valid(input_validity_data *data=nullptr)
static auto it
typename::boost::move_detail::remove_reference< T >::type && move(T &&t) BOOST_NOEXCEPT
void gaussian_filter(std::vector< uint8_t > const &lum_frame, std::vector< uint8_t > const &prev_lum_frame, std::vector< double > &yuy_diff, std::vector< double > &gaussian_filtered_image, size_t width, size_t height)
int i
GLuint res
Definition: glext.h:8856
std::vector< uint8_t > get_logic_edges(std::vector< double > const &edges)
Definition: optimizer.cpp:1287
std::vector< double > gauss_convolution(std::vector< T > const &image, size_t image_width, size_t image_height, size_t mask_width, size_t mask_height, std::function< double(std::vector< T > const &sub_image) > convolution_operation)
Definition: valid-scene.cpp:23
void section_per_pixel(frame_data const &, size_t section_w, size_t section_h, byte *section_map)
Definition: parser.hpp:150
GLint GLsizei width
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:50:14