RSLightFields
Disparity map estimator from 3D light fields
rslf_depth_computation_core.hpp
Go to the documentation of this file.
1 #ifndef _RSLF_DEPTH_COMPUTATION_CORE
2 #define _RSLF_DEPTH_COMPUTATION_CORE
3 
4 #include <chrono>
5 #include <omp.h>
6 
7 #include <opencv2/imgproc/imgproc.hpp>
8 
9 #include <rslf_interpolation.hpp>
10 #include <rslf_kernels.hpp>
11 
12 
13 //~ #define _RSLF_DEPTH_COMPUTATION_DEBUG
14 
15 // Default parameters
16 #define _MEAN_SHIFT_MAX_ITER 10
17 #define _EDGE_CONFIDENCE_FILTER_SIZE 9
18 #define _MEDIAN_FILTER_SIZE 5
19 #define _MEDIAN_FILTER_EPSILON 0.1
20 #define _EDGE_SCORE_THRESHOLD 0.02
21 #define _DISP_SCORE_THRESHOLD 0.01
22 #define _PROPAGATION_EPSILON 0.1
23 
24 #define _BANDWIDTH_KERNEL_PARAMETER 0.2
25 
26 #define _EDGE_CONFIDENCE_OPENING_TYPE cv::MORPH_ELLIPSE
27 #define _EDGE_CONFIDENCE_OPENING_SIZE 1
28 
29 #define _SHADOW_NORMALIZED_LEVEL 0.05 * 1.73205080757
30 // between 0 and 1, 0 being dark and 1 being blank
31 // multiplied by sqrt(3) for consistency with 3channels
32 
33 //~ #define _USE_DISP_CONFIDENCE_SCORE
34 // if not defined, will use C_e as the propagation threshold, else will
35 // use C_d > par_disp_score_threshold.
36 
37 
38 // Useful links
39 // https://docs.opencv.org/3.4.1/
40 // https://docs.opencv.org/3.4.1/d3/d63/classcv_1_1Mat.html
41 // https://docs.opencv.org/3.4.1/d2/de8/group__core__array.html
42 // https://stackoverflow.com/questions/23998422/how-to-access-slices-of-a-3d-matrix-in-opencv
43 // https://stackoverflow.com/questions/2724708/is-it-a-good-practice-to-pass-struct-object-as-parameter-to-a-function-in-c
44 
45 
52 namespace rslf
53 {
54 
55 /*
56  * *****************************************************************
57  * Depth1DParameters
58  * *****************************************************************
59  */
60 
64 template<typename DataType>
66 {
67 private:
68  static Depth1DParameters s_default;
69  bool m_owner_classes = false;
70 
71 public:
72  Depth1DParameters() // initialize at default values
73  {
74  par_interpolation_class = new Interpolation1DLinear<DataType>();
75  //~ par_interpolation_class = new Interpolation1DNearestNeighbour<DataType>();
76  par_kernel_class = new BandwidthKernel<DataType>(_BANDWIDTH_KERNEL_PARAMETER);
77 
78  par_edge_score_threshold = _EDGE_SCORE_THRESHOLD;
79  par_disp_score_threshold = _DISP_SCORE_THRESHOLD;
80  par_mean_shift_max_iter = _MEAN_SHIFT_MAX_ITER;
81 
82  par_edge_confidence_filter_size = _EDGE_CONFIDENCE_FILTER_SIZE;
83  par_edge_confidence_opening_type = _EDGE_CONFIDENCE_OPENING_TYPE;
84  par_edge_confidence_opening_size = _EDGE_CONFIDENCE_OPENING_SIZE;
85 
86  par_median_filter_size = _MEDIAN_FILTER_SIZE;
87  par_median_filter_epsilon = _MEDIAN_FILTER_EPSILON;
88  par_propagation_epsilon = _PROPAGATION_EPSILON;
89 
90  par_slope_factor = 1.0; // Useful when subsampling EPIs
91 
92 
93  }
94 
96  {
98  // Notify the non-ownership of the class pointers
99  m_owner_classes = false;
100  }
101 
102  Interpolation1DClass<DataType>* par_interpolation_class;
103  KernelClass<DataType>* par_kernel_class;
104 
105  float par_edge_score_threshold;
106  float par_disp_score_threshold;
107  float par_mean_shift_max_iter;
108  int par_edge_confidence_filter_size;
109  int par_edge_confidence_opening_type;
110  int par_edge_confidence_opening_size;
111  int par_median_filter_size;
112  float par_median_filter_epsilon;
113  float par_propagation_epsilon;
114  float par_slope_factor;
115 
117  {
118  if (m_owner_classes)
119  {
120  delete par_interpolation_class;
121  delete par_kernel_class;
122  }
123  }
124 
125  static Depth1DParameters& get_default() // get a static default instance
126  {
127  return s_default;
128  }
129 };
130 
131 template<typename DataType>
133 
134 
135 /*
136  * *****************************************************************
137  * compute_1D_depth_epi
138  * *****************************************************************
139  */
144 template <typename DataType>
146 
148  (
149  int a_dim_s,
150  int a_dim_d,
151  int a_dim_u,
152  int a_data_type,
153  const Depth1DParameters<DataType>& a_parameters
154  )
155  {
156  buf_filter_kernel = cv::Mat::zeros(1, a_parameters.par_edge_confidence_filter_size, CV_32FC1);
157  buf_scores_u_d = Mat(a_dim_u, a_dim_d, CV_32FC1, cv::Scalar(0.0));
158 
159  buf_S = Mat(a_dim_s, 1, CV_32FC1);
160  buf_D = Mat(1, a_dim_d, CV_32FC1);
161 
162  buf_card_R = Mat(1, a_dim_d, CV_32FC1);
163  buf_radiances_s_d = cv::Mat::zeros(a_dim_s, a_dim_d, a_data_type);
164  }
165 
166  Vec<cv::Point> buf_locations;
167 
168  Mat buf_scores_u_d;
169 
170  Mat buf_filter_kernel;
171  Mat buf_conv_tmp;
172  Mat buf_sqsum_tmp;
173 
174  Mat buf_I;
175  Mat buf_S;
176  Mat buf_D;
177 
178  Mat buf_radiances_s_d;
179  Mat buf_radiances_s_d_un_nanified;
180  Mat buf_card_R;
181 
182  Mat buf_r_bar;
183  Mat buf_r_m_r_bar;
184  Mat buf_K_r_m_r_bar_mat;
185  Mat buf_K_r_m_r_bar_mat_vec;
186  Mat buf_r_K_r_m_r_bar_mat;
187  Mat buf_sum_r_K_r_m_r_bar;
188  Mat buf_sum_K_r_m_r_bar;
189  Mat buf_sum_K_r_m_r_bar_vec;
190  Mat buf_r_bar_broadcast;
191 };
192 
197 template<typename DataType>
199  const Mat& a_epi,
200  int a_s,
201  Mat& a_edge_confidence_u,
202  Mat& a_edge_confidence_mask_u,
203  const Depth1DParameters<DataType>& a_parameters,
204  BufferDepth1D<DataType>& a_buffer
205 );
206 
211 template<typename DataType>
213  const Mat& a_epi,
214  const Mat& a_dmin_u,
215  const Mat& a_dmax_u,
216  int a_dim_d,
217  int a_s_hat,
218  const Mat& a_edge_confidence_u,
219  const Mat& a_edge_confidence_mask_u,
220  Mat& a_disp_confidence_u,
221  Mat& a_best_depth_u,
222  Mat& a_rbar_u,
223  const Depth1DParameters<DataType>& a_parameters,
224  BufferDepth1D<DataType>& a_buffer,
225  Mat& a_mask_u
226 );
227 
228 /*
229  * *****************************************************************
230  * compute_1D_depth_epi_pile
231  * *****************************************************************
232  */
233 
238 template<typename DataType>
240  const Vec<Mat>& a_epis,
241  int a_s,
242  Mat& a_edge_confidence_v_u,
243  Mat& a_edge_confidence_mask_v_u,
244  const Depth1DParameters<DataType>& a_parameters,
245  Vec<BufferDepth1D<DataType>* >& a_buffers
246 );
247 
252 template<typename DataType>
254  const Vec<Mat>& a_epis,
255  const Mat& a_dmin_v_u,
256  const Mat& a_dmax_v_u,
257  int a_dim_d,
258  int a_s_hat,
259  const Mat& a_edge_confidence_v_u,
260  const Mat& a_edge_confidence_mask_v_u,
261  Mat& a_disp_confidence_v_u,
262  Mat& a_best_depth_v_u,
263  Mat& a_rbar_v_u,
264  const Depth1DParameters<DataType>& a_parameters,
265  Vec<BufferDepth1D<DataType>* >& a_buffers,
266  Mat& a_mask_v_u,
267  bool a_verbose = true
268 );
269 
270 
271 /*
272  * *****************************************************************
273  * compute_2D_depth_epi
274  * *****************************************************************
275  */
276 
281 template<typename DataType>
283  const Vec<Mat>& a_epis,
284  Vec<Mat>& a_edge_confidence_s_v_u,
285  Vec<Mat>& a_edge_confidence_mask_s_v_u,
286  const Depth1DParameters<DataType>& a_parameters,
287  Vec<BufferDepth1D<DataType>* >& a_buffers
288 );
289 
294 template<typename DataType>
296  const Vec<Mat>& a_epis,
297  const Vec<Mat>& a_dmin_s_v_u,
298  const Vec<Mat>& a_dmax_s_v_u,
299  int a_dim_d,
300  const Vec<Mat>& a_edge_confidence_s_v_u,
301  const Vec<Mat>& a_edge_confidence_mask_s_v_u,
302  Vec<Mat>& a_disp_confidence_s_v_u,
303  Vec<Mat>& a_best_depth_s_v_u,
304  Vec<Mat>& a_rbar_s_v_u,
305  const Depth1DParameters<DataType>& a_parameters,
306  Vec<BufferDepth1D<DataType>* >& a_buffers,
307  bool a_verbose = true
308 );
309 
310 
311 
312 /*
313  * *****************************************************************
314  * selective_median_filter
315  * *****************************************************************
316  */
317 
323 template<typename DataType>
325  const Mat& a_src,
326  Mat& a_dst,
327  const Vec<Mat>& a_epis,
328  int a_s_hat,
329  int a_size,
330  const Mat& a_mask_v_u,
331  float a_epsilon
332 );
333 
334 /*
335  * Useful template functions
336  */
337 
345 template<typename DataType>
346 void _square_sum_channels_into(const Mat& src, Mat& dst, Mat& buffer);
347 
356 template<typename DataType>
357 void _multiply_multi_channel(const Mat& line_mat, const Mat& vec_mat, Mat& res_mat, Mat& buffer);
358 
367 template<typename DataType>
368 void _divide_multi_channel(const Mat& line_mat, const Mat& vec_mat, Mat& res_mat, Mat& buffer);
369 
370 
371 
374 
375 
376 
377 /*
378  * *****************************************************************
379  * IMPLEMENTATION
380  * compute_1D_depth_epi
381  * *****************************************************************
382  */
383 template<typename DataType>
384 void compute_1D_edge_confidence(
385  const Mat& a_epi,
386  int a_s,
387  Mat& a_edge_confidence_u,
388  Mat& a_edge_confidence_mask_u,
389  const Depth1DParameters<DataType>& a_parameters,
390  BufferDepth1D<DataType>& a_buffer
391 )
392 {
393  /*
394  * Compute edge confidence
395  */
396  int filter_size = a_parameters.par_edge_confidence_filter_size;
397  int center_index = (filter_size -1) / 2;
398 
399  // Get buffer variables
400  Mat kernel = a_buffer.buf_filter_kernel;
401  Mat tmp = a_buffer.buf_conv_tmp;
402  Mat tmp2 = a_buffer.buf_sqsum_tmp;
403 
404  cv::Point tmp_param(-1,-1);
405 
406  for (int j=0; j<filter_size; j++)
407  {
408  if (j == center_index)
409  continue;
410 
411  // Make filter with 1 at 1, 1 and -1 at i, j
412  kernel.setTo(0.0);
413  kernel.at<float>(center_index) = 1.0;
414  kernel.at<float>(j) = -1.0;
415  cv::filter2D(a_epi.row(a_s), tmp, -1, kernel, tmp_param, 0, cv::BORDER_REFLECT_101);
416 
417  // Sum square values into edge confidence
418  _square_sum_channels_into<DataType>(tmp, a_edge_confidence_u, tmp2);
419  }
420 
421  // TODO
422  // Dirty way to remove all dark pixels
423  // Get elementwise norm
424  Mat im_norm = Mat(1, a_edge_confidence_u.cols, CV_32FC1);
425  for (int u=0; u<a_edge_confidence_u.cols; u++)
426  {
427  im_norm.at<float>(u) = norm<DataType>(a_epi.row(a_s).at<DataType>(u));
428  }
429  a_edge_confidence_u.setTo(0.0, im_norm < _SHADOW_NORMALIZED_LEVEL);
430 
431  a_edge_confidence_mask_u = a_edge_confidence_u > a_parameters.par_edge_score_threshold;
432 
433 }
434 
435 template<typename DataType>
436 void compute_1D_depth_epi(
437  const Mat& a_epi,
438  const Mat& a_dmin_u,
439  const Mat& a_dmax_u,
440  int a_dim_d,
441  int a_s_hat,
442  const Mat& a_edge_confidence_u,
443  const Mat& a_edge_confidence_mask_u,
444  Mat& a_disp_confidence_u,
445  Mat& a_best_depth_u,
446  Mat& a_rbar_u,
447  const Depth1DParameters<DataType>& a_parameters,
448  BufferDepth1D<DataType>& a_buffer,
449  Mat& a_mask_u
450 )
451 {
452  // Dimensions
453  int dim_s = a_epi.rows;
454 
455  // Init score matrix
456  Mat scores_u_d = a_buffer.buf_scores_u_d;
457 
458  /*
459  * Iterate over all columns of the EPI
460  */
461 
462  // Get indices u to compute
463  // Do not compute low-confidence values or value masked
464  if (!a_mask_u.empty())
465  cv::bitwise_and(a_edge_confidence_mask_u, a_mask_u, a_mask_u);
466  else
467  a_mask_u = a_edge_confidence_mask_u;
468 
469  Vec<cv::Point> locations = a_buffer.buf_locations;
470  cv::findNonZero(a_mask_u, locations);
471 
472  for (auto it = locations.begin(); it<locations.end(); it++)
473  {
474  int u = (*it).x;
475 
476  /*
477  * Fill radiances
478  */
479  // Matrix of indices corresponding to the lines of disparities d
480  Mat I = a_buffer.buf_I;
481  Mat S = a_buffer.buf_S;
482  Mat D = a_buffer.buf_D;
483 
484  // Col matrix
485  for (int s=0; s<dim_s; s++)
486  {
487  S.at<float>(s) = a_s_hat - s;
488  }
489 
490  float dmin = a_dmin_u.at<float>(u);
491  float dmax = a_dmax_u.at<float>(u);
492  for (int d=0; d<a_dim_d; d++)
493  D.at<float>(d) = dmin + d * (dmax - dmin) / (a_dim_d-1);
494 
495  I = S * D;
496  I *= a_parameters.par_slope_factor;
497  I += u;
498 
499  // Radiances
500  Mat radiances_s_d = a_buffer.buf_radiances_s_d;
501  Mat radiances_s_d_un_nanified = a_buffer.buf_radiances_s_d_un_nanified;
502 
503  // Interpolate
504  // TODO this step is costly
505  Mat card_R = a_buffer.buf_card_R;
506  a_parameters.par_interpolation_class->interpolate_mat(a_epi, I, radiances_s_d, card_R);
507 
508  /*
509  * Compute r_bar iteratively
510  */
511  Mat r_bar = a_buffer.buf_r_bar;
512  Mat r_m_r_bar = a_buffer.buf_r_m_r_bar;
513  Mat K_r_m_r_bar_mat = a_buffer.buf_K_r_m_r_bar_mat;
514  Mat K_r_m_r_bar_mat_vec = a_buffer.buf_K_r_m_r_bar_mat_vec;
515  Mat r_K_r_m_r_bar_mat = a_buffer.buf_r_K_r_m_r_bar_mat;
516  Mat sum_r_K_r_m_r_bar = a_buffer.buf_sum_r_K_r_m_r_bar;
517  Mat sum_K_r_m_r_bar = a_buffer.buf_sum_K_r_m_r_bar;
518  Mat sum_K_r_m_r_bar_vec = a_buffer.buf_sum_K_r_m_r_bar_vec;
519  Mat r_bar_broadcast = a_buffer.buf_r_bar_broadcast;
520 
521  // Initialize r_bar to the values in s_hat
522  radiances_s_d.row(a_s_hat).copyTo(r_bar);
523 
524  // Replace nans with zeros (since these will be multiplied by zero anyway)
525  cv::max(radiances_s_d, cv::Scalar(0.0), radiances_s_d_un_nanified);
526 
527  // Perform a partial mean shift to compute r_bar
528  // TODO: This step is costly
529  for (int i=0; i< a_parameters.par_mean_shift_max_iter; i++)
530  {
531  // r_bar repeated over lines
532  cv::repeat(r_bar, dim_s, 1, r_bar_broadcast);
533 
534  // r - r_bar
535  // This matrix contains nans
536  cv::subtract(radiances_s_d, r_bar_broadcast, r_m_r_bar);
537 
538  // K(r - r_bar)
539  // Kernel fuction returns 0 if value is nan
540  a_parameters.par_kernel_class->evaluate_mat(r_m_r_bar, K_r_m_r_bar_mat);
541 
542  // r * K(r - r_bar)
543  // Multiply should be of the same number of channels
544  _multiply_multi_channel<DataType>(K_r_m_r_bar_mat, radiances_s_d_un_nanified, r_K_r_m_r_bar_mat, K_r_m_r_bar_mat_vec);
545 
546  // Sum over lines
547  cv::reduce(r_K_r_m_r_bar_mat, sum_r_K_r_m_r_bar, 0, cv::REDUCE_SUM);
548  cv::reduce(K_r_m_r_bar_mat, sum_K_r_m_r_bar, 0, cv::REDUCE_SUM);
549 
550  // Divide should be of the same number of channels
551  _divide_multi_channel<DataType>(sum_K_r_m_r_bar, sum_r_K_r_m_r_bar, r_bar, sum_K_r_m_r_bar_vec);
552 
553  // Set nans to zero
554  cv::max(r_bar, cv::Scalar(0.0), r_bar);
555  }
556 
557  /*
558  * Compute scores
559  */
560  // Get the last sum { K(r - r_bar) }
561  a_parameters.par_kernel_class->evaluate_mat(r_m_r_bar, K_r_m_r_bar_mat);
562  cv::reduce(K_r_m_r_bar_mat, sum_K_r_m_r_bar, 0, cv::REDUCE_SUM);
563 
564  // Get score
565  cv::divide(sum_K_r_m_r_bar, card_R, sum_K_r_m_r_bar);
566  // Set nans to zero
567  cv::max(sum_K_r_m_r_bar, cv::Scalar(0.0), sum_K_r_m_r_bar);
568 
569  // Copy the line to the scores
570  sum_K_r_m_r_bar.copyTo(scores_u_d.row(u));
571 
572  /*
573  * Get best d (max score)
574  */
575  double minVal;
576  double maxVal;
577  cv::Point minIdx;
578  cv::Point maxIdx;
579  cv::minMaxLoc(scores_u_d.row(u), &minVal, &maxVal, &minIdx, &maxIdx);
580 
581  a_best_depth_u.at<float>(u) = D.at<float>(maxIdx.x);
582 
583  // Compute depth confidence score
584  a_disp_confidence_u.at<float>(u) = a_edge_confidence_u.at<float>(u) * std::abs(maxVal - cv::mean(scores_u_d.row(u))[0]);
585 
586  // Get final r_bar
587  a_rbar_u.at<DataType>(u) = r_bar.at<DataType>(maxIdx.x);
588 
589  }
590 
591 }
592 
593 template<typename DataType>
594 void selective_median_filter(
595  const Mat& a_src,
596  Mat& a_dst,
597  const Vec<Mat>& a_epis,
598  int a_s_hat,
599  int a_size,
600  const Mat& a_mask_v_u,
601  float a_epsilon
602 )
603 {
604  int dim_v = a_src.rows;
605  int dim_u = a_src.cols;
606 
607  // Allocate matrix if not allocated yet
608  if (a_dst.empty() || a_dst.size != a_src.size || a_dst.type() != a_src.type())
609  a_dst = Mat(dim_v, dim_u, a_src.type(), cv::Scalar(0.0));
610 
611  int thr_max = omp_get_max_threads();
612  Vec<Vec<float> > value_buffers;
613  for (int t=0; t<thr_max; t++)
614  value_buffers.push_back(Vec<float>());
615 
616  int width = (a_size-1)/2;
617 
618 #pragma omp parallel for
619  for (int v=0; v<dim_v; v++)
620  {
621  Vec<float> buffer = value_buffers[omp_get_thread_num()];
622  for (int u=0; u<dim_u; u++)
623  {
624  // If mask is null, skip
625  if (a_mask_v_u.at<uchar>(v, u))
626  {
627  buffer.clear();
628  for (int k=std::max(0, v-width); k<std::min(dim_v, v+width+1); k++)
629  {
630  for (int l=std::max(0, u-width); l<std::min(dim_u, u+width+1); l++)
631  {
632  if (a_mask_v_u.at<uchar>(k, l) &&
633  norm(
634  a_epis[v].at<DataType>(a_s_hat, u) -
635  a_epis[k].at<DataType>(a_s_hat, l)
636  ) < a_epsilon)
637  {
638  buffer.push_back(a_src.at<float>(k, l));
639  }
640  }
641  }
642  // Compute the median
643  std::nth_element(buffer.begin(), buffer.begin() + buffer.size() / 2, buffer.end());
644  a_dst.at<float>(v, u) = buffer[buffer.size() / 2];
645  }
646  }
647  }
648 }
649 
650 
651 /*
652  * *****************************************************************
653  * IMPLEMENTATION
654  * compute_1D_depth_epi_pile
655  * *****************************************************************
656  */
657 
658 template<typename DataType>
659 void compute_1D_edge_confidence_pile(
660  const Vec<Mat>& a_epis,
661  int a_s,
662  Mat& a_edge_confidence_v_u,
663  Mat& a_edge_confidence_mask_v_u,
664  const Depth1DParameters<DataType>& a_parameters,
665  Vec<BufferDepth1D<DataType>* >& a_buffers
666 )
667 {
668  int dim_v = a_epis.size();
669 
670  a_edge_confidence_mask_v_u = Mat(a_edge_confidence_v_u.rows, a_edge_confidence_v_u.cols, CV_8UC1);
671 
672  // Compute edge confidence for all rows
673 #pragma omp parallel for
674  for (int v=0; v<dim_v; v++)
675  {
676  Mat edge_confidence_u = a_edge_confidence_v_u.row(v);
677  Mat edge_confidence_mask_u = a_edge_confidence_mask_v_u.row(v);
678 
679  compute_1D_edge_confidence<DataType>(
680  a_epis[v],
681  a_s,
682  edge_confidence_u,
683  edge_confidence_mask_u,
684  a_parameters,
685  *a_buffers[omp_get_thread_num()]
686  );
687  }
688 
689  if (a_parameters.par_edge_confidence_opening_size > 1)
690  {
691  // Perform a morphological opening on the result
692  Mat kernel = cv::getStructuringElement
693  (
694  a_parameters.par_edge_confidence_opening_type,
695  cv::Size(a_parameters.par_edge_confidence_opening_size, a_parameters.par_edge_confidence_opening_size)
696  );
697 
698  cv::morphologyEx(a_edge_confidence_mask_v_u, a_edge_confidence_mask_v_u, cv::MORPH_OPEN, kernel);
699  }
700 }
701 
702 template<typename DataType>
703 void compute_1D_depth_epi_pile(
704  const Vec<Mat>& a_epis,
705  const Mat& a_dmin_v_u,
706  const Mat& a_dmax_v_u,
707  int a_dim_d,
708  int a_s_hat,
709  const Mat& a_edge_confidence_v_u,
710  const Mat& a_edge_confidence_mask_v_u,
711  Mat& a_disp_confidence_v_u,
712  Mat& a_best_depth_v_u,
713  Mat& a_rbar_v_u,
714  const Depth1DParameters<DataType>& a_parameters,
715  Vec<BufferDepth1D<DataType>* >& a_buffers,
716  Mat& a_mask_v_u,
717  bool a_verbose
718 )
719 {
720  // Dimension
721  int dim_v = a_epis.size();
722 
723  // For progress bar
724  float progress = 0.0;
725  int barWidth = 40;
726  std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
727 
728 #pragma omp parallel for
729  for (int v=0; v<dim_v; v++)
730  {
731  // Create views
732  Mat epi = a_epis[v];
733  Mat dmin_u = a_dmin_v_u.row(v);
734  Mat dmax_u = a_dmax_v_u.row(v);
735  Mat edge_confidence_u = a_edge_confidence_v_u.row(v);
736  Mat edge_confidence_mask_u = a_edge_confidence_mask_v_u.row(v);
737  Mat disp_confidence_u = a_disp_confidence_v_u.row(v);
738  Mat best_depth_u = a_best_depth_v_u.row(v);
739  Mat rbar_u = a_rbar_v_u.row(v);
740 
741  // Empty mask -> no masked point
742  Mat mask_u;
743  if (!a_mask_v_u.empty())
744  mask_u = a_mask_v_u.row(v);
745 
746  compute_1D_depth_epi<DataType>(
747  epi,
748  dmin_u,
749  dmax_u,
750  a_dim_d,
751  a_s_hat,
752  edge_confidence_u,
753  edge_confidence_mask_u,
754  disp_confidence_u,
755  best_depth_u,
756  rbar_u,
757  a_parameters,
758  *a_buffers[omp_get_thread_num()],
759  mask_u
760  );
761 
762  if (a_verbose)
763  {
764 #pragma omp critical
765 {
766  // Display progress bar
767  std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
768  std::cout << "[";
769  int pos = barWidth * progress / dim_v;
770  for (int i = 0; i < barWidth; ++i) {
771  if (i < pos) std::cout << "=";
772  else if (i == pos) std::cout << ">";
773  else std::cout << " ";
774  }
775  std::cout << "] " << int(progress * 100.0 / dim_v) << "% \t" << std::chrono::duration_cast<std::chrono::seconds>( t2 - t1 ).count() << "s \r";
776  std::cout.flush();
777 }
778 #pragma omp atomic
779  progress += 1.0;
780  }
781  }
782 
783  // Apply median filter
784  if (a_verbose)
785  std::cout << std::endl << "Applying selective median fiter" << std::endl;
786 
787  Mat tmp;
788  selective_median_filter<DataType>(
789  a_best_depth_v_u,
790  tmp,
791  a_epis,
792  a_s_hat,
793  a_parameters.par_median_filter_size,
794  a_edge_confidence_mask_v_u,
795  a_parameters.par_median_filter_epsilon
796  );
797 
798  a_best_depth_v_u = tmp;
799 }
800 
801 /*
802  * *****************************************************************
803  * IMPLEMENTATION
804  * compute_2D_depth_epi
805  * *****************************************************************
806  */
807 template<typename DataType>
808 void compute_2D_edge_confidence(
809  const Vec<Mat>& a_epis,
810  Vec<Mat>& a_edge_confidence_s_v_u,
811  Vec<Mat>& a_edge_confidence_mask_s_v_u,
812  const Depth1DParameters<DataType>& a_parameters,
813  Vec<BufferDepth1D<DataType>* >& a_buffers
814 )
815 {
816  int dim_s = a_epis[0].rows;
817 
818  a_edge_confidence_mask_s_v_u.clear();
819 
820  // Compute edge confidence for all rows
821  for (int s=0; s<dim_s; s++)
822  {
823  Mat edge_confidence_v_u = a_edge_confidence_s_v_u[s];
824  Mat edge_confidence_mask_v_u;
825 
826  compute_1D_edge_confidence_pile(
827  a_epis,
828  s,
829  edge_confidence_v_u,
830  edge_confidence_mask_v_u,
831  a_parameters,
832  a_buffers
833  );
834 
835  a_edge_confidence_mask_s_v_u.push_back(edge_confidence_mask_v_u);
836  }
837 }
838 
839 template<typename DataType>
840 void compute_2D_depth_epi(
841  const Vec<Mat>& a_epis,
842  const Vec<Mat>& a_dmin_s_v_u,
843  const Vec<Mat>& a_dmax_s_v_u,
844  int a_dim_d,
845  const Vec<Mat>& a_edge_confidence_s_v_u,
846  const Vec<Mat>& a_edge_confidence_mask_s_v_u,
847  Vec<Mat>& a_disp_confidence_s_v_u,
848  Vec<Mat>& a_best_depth_s_v_u,
849  Vec<Mat>& a_rbar_s_v_u,
850  const Depth1DParameters<DataType>& a_parameters,
851  Vec<BufferDepth1D<DataType>* >& a_buffers,
852  bool a_verbose
853 )
854 {
855  int dim_s = a_epis[0].rows;
856  int dim_u = a_epis[0].cols;
857  int dim_v = a_epis.size();
858  int s_hat = (int)std::floor(dim_s / 2.0);
859 
860  // Assume edge confidence is computed on all the image
861 
862  // Create a mask (CV_8UC1) and init to C_e > thr
863  Vec<Mat> mask_s_v_u = Vec<Mat>(dim_s);
864  for (int s=0; s<dim_s; s++)
865  {
866  // TODO other criteria?
867  mask_s_v_u[s] = a_edge_confidence_mask_s_v_u[s].clone();
868  }
869 
870  Mat dmin_v_u;
871  Mat dmax_v_u;
872  Mat edge_confidence_v_u;
873  Mat edge_confidence_mask_v_u;
874  Mat disp_confidence_v_u;
875  Mat best_depth_v_u;
876  Mat rbar_v_u;
877  Mat mask_v_u;
878 
879  Vec<int> s_values;
880  s_values.push_back(s_hat);
881  for (int s_offset=1; s_offset<dim_s-s_hat; s_offset++)
882  {
883  int s_sup = s_hat + s_offset;
884  int s_inf = s_hat - s_offset;
885  s_values.push_back(s_sup);
886  if (s_inf > -1)
887  s_values.push_back(s_inf);
888  }
889 
890  // Iterate over lines of the epi (s) starting from the middle
891  for (auto it = s_values.begin(); it < s_values.end(); it++)
892  {
893  int s_hat = *it;
894 
895  if (a_verbose)
896  std::cout << "Computing s_hat=" << s_hat << std::endl;
897 
898  dmin_v_u = a_dmin_s_v_u[s_hat];
899  dmax_v_u = a_dmax_s_v_u[s_hat];
900  edge_confidence_v_u = a_edge_confidence_s_v_u[s_hat];
901  edge_confidence_mask_v_u = a_edge_confidence_mask_s_v_u[s_hat];
902  disp_confidence_v_u = a_disp_confidence_s_v_u[s_hat];
903  best_depth_v_u = a_best_depth_s_v_u[s_hat];
904  rbar_v_u = a_rbar_s_v_u[s_hat];
905  mask_v_u = mask_s_v_u[s_hat];
906 
907  compute_1D_depth_epi_pile<DataType>(
908  a_epis,
909  dmin_v_u,
910  dmax_v_u,
911  a_dim_d,
912  s_hat,
913  edge_confidence_v_u,
914  edge_confidence_mask_v_u,
915  disp_confidence_v_u,
916  best_depth_v_u,
917  rbar_v_u,
918  a_parameters,
919  a_buffers,
920  mask_v_u,
921  false // verbose
922  );
923 
924  if (a_verbose)
925  std::cout << "Propagation..." << std::endl;
926 
927  // Propagate depths over lines and update further mask lines
928  // For each column of the s_hat row, draw the line, taking overlays into account
929 #pragma omp parallel for
930  for (int v=0; v<dim_v; v++)
931  {
932  Mat edge_confidence_u = edge_confidence_v_u.row(v);
933  Mat best_depth_u = best_depth_v_u.row(v);
934  Mat rbar_u = rbar_v_u.row(v);
935  for (int u=0; u<dim_u; u++)
936  {
937  // Only paint if the confidence threshold was high enough
938 #ifdef _USE_DISP_CONFIDENCE_SCORE
939  if (disp_confidence_v_u.at<float>(v, u) > a_parameters.par_disp_score_threshold)
940 #else
941  if (edge_confidence_mask_v_u.at<uchar>(v, u))
942 #endif
943  {
944  float current_depth_value = best_depth_u.at<float>(u);
945  for (int s=0; s<dim_s; s++)
946  {
947 
948  int requested_index = u + (int)std::round(best_depth_u.at<float>(u) * (s_hat - s) * a_parameters.par_slope_factor);
949 
950  if
951  (
952  requested_index > -1 &&
953  requested_index < dim_u &&
954  mask_s_v_u[s].at<uchar>(v, requested_index) == 255 &&
955  norm<DataType>(a_epis[v].at<DataType>(s, requested_index) - rbar_u.at<DataType>(u)) < a_parameters.par_propagation_epsilon
956  )
957  {
958  a_best_depth_s_v_u[s].at<float>(v, requested_index) = current_depth_value;
959  mask_s_v_u[s].at<uchar>(v, requested_index) = 0;
960  a_disp_confidence_s_v_u[s].at<float>(v, requested_index) = disp_confidence_v_u.at<float>(v, u);
961  }
962  }
963  }
964  }
965  }
966 
967  }
968 
969 }
970 
971 }
972 
973 
974 
975 #endif
void _divide_multi_channel(const Mat &line_mat, const Mat &vec_mat, Mat &res_mat, Mat &buffer)
Divide a vec matrix by a line matrix elementwise broadcasting the line matrix over channels of the ve...
Impelment a structure containing all the algorithm parameters.
Definition: rslf_depth_computation_core.hpp:65
Implement a buffer containing re-usable temporary variables in order to avoid multiple unnecessary al...
Definition: rslf_depth_computation_core.hpp:145
void compute_1D_depth_epi(const Mat &a_epi, const Mat &a_dmin_u, const Mat &a_dmax_u, int a_dim_d, int a_s_hat, const Mat &a_edge_confidence_u, const Mat &a_edge_confidence_mask_u, Mat &a_disp_confidence_u, Mat &a_best_depth_u, Mat &a_rbar_u, const Depth1DParameters< DataType > &a_parameters, BufferDepth1D< DataType > &a_buffer, Mat &a_mask_u)
Given a single EPI along dimensions (s, u) (v is fixed), compute the slopes only looking at a single ...
Definition: rslf_depth_computation_core.hpp:436
Template linear interpolation class.
Definition: rslf_interpolation.hpp:59
std::vector< T > Vec
RSLF Vector class (std::vector)
Definition: rslf_types.hpp:32
void selective_median_filter(const Mat &a_src, Mat &a_dst, const Vec< Mat > &a_epis, int a_s_hat, int a_size, const Mat &a_mask_v_u, float a_epsilon)
Filter the given spatial image of dimensions (v, u) using a selective median filter (only points with...
Definition: rslf_depth_computation_core.hpp:594
Definition: rslf_depth_computation.hpp:14
void compute_1D_edge_confidence_pile(const Vec< Mat > &a_epis, int a_s, Mat &a_edge_confidence_v_u, Mat &a_edge_confidence_mask_v_u, const Depth1DParameters< DataType > &a_parameters, Vec< BufferDepth1D< DataType > * > &a_buffers)
Given a vector of EPIs, compute the edge confidence along the line of given index s along the dimensi...
Definition: rslf_depth_computation_core.hpp:659
float norm(DataType x)
Implement the euclidean norm.
void compute_2D_depth_epi(const Vec< Mat > &a_epis, const Vec< Mat > &a_dmin_s_v_u, const Vec< Mat > &a_dmax_s_v_u, int a_dim_d, const Vec< Mat > &a_edge_confidence_s_v_u, const Vec< Mat > &a_edge_confidence_mask_s_v_u, Vec< Mat > &a_disp_confidence_s_v_u, Vec< Mat > &a_best_depth_s_v_u, Vec< Mat > &a_rbar_s_v_u, const Depth1DParameters< DataType > &a_parameters, Vec< BufferDepth1D< DataType > * > &a_buffers, bool a_verbose=true)
Given a vector of EPIs, compute the disparities for all points (s, v, u) using the propagation proces...
Definition: rslf_depth_computation_core.hpp:840
Pure virtual class implementing a generic kernel instance.
Definition: rslf_kernels.hpp:21
void compute_1D_depth_epi_pile(const Vec< Mat > &a_epis, const Mat &a_dmin_v_u, const Mat &a_dmax_v_u, int a_dim_d, int a_s_hat, const Mat &a_edge_confidence_v_u, const Mat &a_edge_confidence_mask_v_u, Mat &a_disp_confidence_v_u, Mat &a_best_depth_v_u, Mat &a_rbar_v_u, const Depth1DParameters< DataType > &a_parameters, Vec< BufferDepth1D< DataType > * > &a_buffers, Mat &a_mask_v_u, bool a_verbose=true)
For every EPI in the given vector (i.e. for all v), compute the slopes only looking at a single line ...
Definition: rslf_depth_computation_core.hpp:703
void compute_2D_edge_confidence(const Vec< Mat > &a_epis, Vec< Mat > &a_edge_confidence_s_v_u, Vec< Mat > &a_edge_confidence_mask_s_v_u, const Depth1DParameters< DataType > &a_parameters, Vec< BufferDepth1D< DataType > * > &a_buffers)
Given a vector of EPIs, compute the edge confidence on all lines for all EPIs (so that an edge confid...
Definition: rslf_depth_computation_core.hpp:808
void _square_sum_channels_into(const Mat &src, Mat &dst, Mat &buffer)
Sum the squares of the values across channels of the input matrix.
cv::Mat Mat
RSLF Matrix class (cv::Mat)
Definition: rslf_types.hpp:26
This kernel returns value: 1 - norm(x/h)^2 if norm(x/h) < 1, 0 else.
Definition: rslf_kernels.hpp:40
void _multiply_multi_channel(const Mat &line_mat, const Mat &vec_mat, Mat &res_mat, Mat &buffer)
Multiply a vec matrix by a line matrix elementwise broadcasting the line matrix over channels of the ...
Pure virtual class implementing a generic interpolation instance.
Definition: rslf_interpolation.hpp:28
void compute_1D_edge_confidence(const Mat &a_epi, int a_s, Mat &a_edge_confidence_u, Mat &a_edge_confidence_mask_u, const Depth1DParameters< DataType > &a_parameters, BufferDepth1D< DataType > &a_buffer)
Compute the edge confidence score for a single line along the dimension u.
Definition: rslf_depth_computation_core.hpp:384