1 // This is brl/bseg/bsgm/bsgm_disparity_estimator.h
2 #ifndef bsgm_multiscale_disparity_estimator_h_
3 #define bsgm_multiscale_disparity_estimator_h_
4 
5 #include <string>
6 #include <vector>
7 #include <set>
8 #include <iostream>
9 #include <sstream>
10 #include <utility>
11 
12 #include <vul/vul_timer.h>
13 #include <vnl/vnl_math.h>
14 #include <vil/vil_image_view.h>
15 #include "vil/vil_resample_nearest.h"
16 #include "vil/vil_resample_bilin.h"
17 #include <vil/algo/vil_structuring_element.h>
18 #include <vil/algo/vil_sobel_3x3.h>
19 #include <vil/algo/vil_median.h>
20 #include <vil/algo/vil_binary_dilate.h>
21 #include <vil/algo/vil_gauss_reduce.h>
22 
23 #include "bsgm_disparity_estimator.h"
24 
25 //:
26 // \file
27 // \brief A multi-scale implementation of SGM.
28 // \author Thomas Pollard
29 // \date June 7, 2016
30 //
31 //  Modifications
32 //   Jun, 2016 Yi Dong - add input parameter for function 'compute'
33 // \endverbatim
34 
35 
36 class bsgm_multiscale_disparity_estimator
37 {
38  public:
39 
40   //: Construct from parameters. Coarse scale SGM will run on images
41   // downsampled by 2^downscale_exponent
42   bsgm_multiscale_disparity_estimator(
43     const bsgm_disparity_estimator_params& params,
44     int img_width,
45     int img_height,
46     int num_disparities,
47     int num_active_disparities,
48     int downscale_exponent = 2 );
49 
50   //: Destructor
51   ~bsgm_multiscale_disparity_estimator();
52 
53   //: Run SGM twice, once at a lower resolution to determine the active
54   // disparity range, and again at full-res using the reduced disparity range.
55   // Should improve speed and quality with respect to single-scale approach if
56   // tight disparity bounds are unknown.
57   // mutli_scale_mode can be:
58   // 0 Single min disparity used for entire image
59   // 1 Single min disparity used within coarse image blocks
60   // 2 Different min disparity used at each pixel
61   template <class T>
62   bool compute(
63     const vil_image_view<T>& img_target,
64     const vil_image_view<T>& img_ref,
65     const vil_image_view<bool>& invalid_target,
66     int min_disparity,
67     float invalid_disparity,
68     int const& multi_scale_mode,
69     vil_image_view<float>& disp_target,
70     float dynamic_range_factor = 1.0f,
71     bool skip_error_check = false);
72 
73   //: Same as above, except compute disparity maps for both images and use a
74   // full left-right consistency check to detect and fix errors in the
75   // disparity maps.
76   template <class T>
77   bool compute_both(
78     const vil_image_view<T>& img_target,
79     const vil_image_view<T>& img_ref,
80     const vil_image_view<bool>& invalid_target,
81     const vil_image_view<bool>& invalid_ref,
82     int min_disparity,
83     float invalid_disparity,
84     int const& multi_scale_mode,
85     vil_image_view<float>& disp_target,
86     vil_image_view<float>& disp_ref,
87     float dynamic_range_factor = 1.0f);
88 
89   //: Write out the appearance or total cost volume as a set of images for
90   // debugging
91   void write_cost_debug_imgs(
92     const std::string& out_dir,
93     bool write_total_cost = false )
94   {
95     fine_de_->write_cost_debug_imgs(out_dir, write_total_cost);
96   }
97 
98  protected:
99 int bsgm_compute_median_of_image(
100   const vil_image_view<float>& img,
101   const vil_image_view<bool>& invalid,
102   int start_x,
103   int end_x,
104   int start_y,
105   int end_y,
106   int min_img_val,
107   int num_img_vals,
108   float invalid_disparity );
109   //: Size of image
110   int coarse_w_, coarse_h_, fine_w_, fine_h_;
111 
112   //: Downscaling parameters where downscale_factor_ = 2^downscale_exponent_
113   int downscale_exponent_;
114   int downscale_factor_;
115 
116   int num_coarse_disparities_, num_fine_disparities_, num_active_disparities_;
117 
118   //: Single-scale SGMs for coarse and fine scales
119   bsgm_disparity_estimator* coarse_de_;
120   bsgm_disparity_estimator* fine_de_;
121   bsgm_disparity_estimator_params params_;
122 };
123 template <class T>
compute(const vil_image_view<T> & img_tar,const vil_image_view<T> & img_ref,const vil_image_view<bool> & invalid_tar,int min_disp,float invalid_disp,int const & multi_scale_mode,vil_image_view<float> & disp_tar,float dynamic_range_factor,bool skip_error_check)124 bool bsgm_multiscale_disparity_estimator::compute(
125   const vil_image_view<T>& img_tar,
126   const vil_image_view<T>& img_ref,
127   const vil_image_view<bool>& invalid_tar,
128   int min_disp,
129   float invalid_disp,
130   int const& multi_scale_mode,
131   vil_image_view<float>& disp_tar,
132   float dynamic_range_factor,
133   bool skip_error_check)
134 {
135   //int multi_scale_mode = 1;
136 
137   // Size of block used in mode 1
138   int block_size = 100;
139   disp_tar.set_size( fine_w_, fine_h_ );
140 
141   // Validate images.
142   if( img_tar.ni() != fine_w_ || img_tar.nj() != fine_h_ ||
143       img_ref.ni() != fine_w_ || img_ref.nj() != fine_h_ ||
144       invalid_tar.ni() != fine_w_ || invalid_tar.nj() != fine_h_ )
145     return false;
146 
147   // Downsample the images
148   vil_image_view<T> img_t_coarse, img_r_coarse,
149     temp_t_coarse, temp_r_coarse, working;
150 
151   vil_gauss_reduce( img_tar, img_t_coarse, working );
152   vil_gauss_reduce( img_ref, img_r_coarse, working );
153 
154   for( int s = 1; s < downscale_exponent_; s++ ){
155     vil_gauss_reduce( img_t_coarse, temp_t_coarse, working );
156     img_t_coarse.deep_copy( temp_t_coarse );
157     vil_gauss_reduce( img_r_coarse, temp_r_coarse, working );
158     img_r_coarse.deep_copy( temp_r_coarse );
159   }
160 
161   // Downsample the invalid image and dilate to handle borders
162   vil_image_view<bool> invalid_t_resamp( coarse_w_, coarse_h_ );
163   vil_resample_nearest( invalid_tar, invalid_t_resamp, coarse_w_, coarse_h_ );
164   vil_image_view<bool> invalid_t_coarse( coarse_w_, coarse_h_ );
165   vil_structuring_element se; se.set_to_disk( 3.0 );
166   vil_binary_dilate( invalid_t_resamp, invalid_t_coarse, se );
167 
168   vil_image_view<int> min_disp_img_coarse( coarse_w_, coarse_h_ );
169   vil_image_view<int> min_disp_img_fine( fine_w_, fine_h_ );
170 
171   // Setup trivial coarse-scale min disparity image
172   int min_disp_coarse = min_disp / downscale_factor_;
173   min_disp_img_coarse.fill( min_disp_coarse );
174 
175   float invalid_disp_coarse = invalid_disp / downscale_factor_;
176 
177   // Run SGM on coarse scale images
178   vil_image_view<float> disp_t_coarse;
179   if( !coarse_de_->compute( img_t_coarse, img_r_coarse, invalid_t_coarse,
180      min_disp_img_coarse, invalid_disp_coarse, disp_t_coarse, dynamic_range_factor ) )
181     return false;
182 
183   //DEBUG
184   //vil_save( disp_t_coarse, "D:/temp/sgm/mountain_pair/disp_t_coarse.tif");
185 
186 
187   // Mode 0 uses a constant min disparity for all pixels
188   if( multi_scale_mode == 0 ){
189 
190     // Compute the median disparity for the
191     int med_ds = bsgm_compute_median_of_image(
192       disp_t_coarse, invalid_t_coarse, 0, coarse_w_, 0, coarse_h_,
193       min_disp_coarse, num_coarse_disparities_, invalid_disp_coarse );
194 
195     // Setup fine-scale min disparity image
196     min_disp_img_fine.fill(
197       med_ds*downscale_factor_ - num_active_disparities_/2 );
198 
199   // Mode 1 uses a fixed min disparity in large block regions
200   } else if( multi_scale_mode == 1 ) {
201 
202     int coarse_block_size = block_size / downscale_factor_;
203 
204     for( int start_y = 0; start_y < coarse_h_; start_y+=coarse_block_size ){
205       for( int start_x = 0; start_x < coarse_w_; start_x+=coarse_block_size ){
206 
207         int end_x = std::min( coarse_w_, start_x+coarse_block_size );
208         int end_y = std::min( coarse_h_, start_y+coarse_block_size );
209 
210         // Compute median of the box region
211         int med_ds = bsgm_compute_median_of_image( disp_t_coarse,
212           invalid_t_coarse, start_x, end_x, start_y, end_y,
213           min_disp_coarse, num_coarse_disparities_, invalid_disp_coarse );
214 
215         // Set the min (fine-scale) disparity for each pixel in the box to a
216         // value centered on this median.
217         for( int by = start_y; by < end_y; by++ ){
218           for( int bx = start_x; bx < end_x; bx++ ){
219             min_disp_img_coarse(bx,by) =
220               med_ds*downscale_factor_ - num_active_disparities_/2;
221           }
222         }
223       }
224     }
225 
226     // Upscale to full-res
227     vil_resample_bilin(
228       min_disp_img_coarse, min_disp_img_fine, fine_w_, fine_h_ );
229 
230   // Mode 2 uses per pixel min disparity based on coarse disparity
231   } else {
232 
233     // Set the min (fine-scale) disparity for each pixel to a value
234     // value centered on this median.
235     for( int y = 0; y < coarse_h_; y++ ){
236       for( int x = 0; x < coarse_w_; x++ ){
237         min_disp_img_coarse(x,y) =
238          disp_t_coarse(x,y)*downscale_factor_ - num_active_disparities_/2;
239       }
240     }
241 
242     // Upscale to full-res
243     vil_resample_bilin(
244       min_disp_img_coarse, min_disp_img_fine, fine_w_, fine_h_ );
245   }
246 
247   // Run fine-scale SGM
248   if( !fine_de_->compute( img_tar, img_ref, invalid_tar,
249       min_disp_img_fine, invalid_disp, disp_tar, dynamic_range_factor, skip_error_check ) )
250     return false;
251 
252   //fine_de_->write_cost_debug_imgs( std::string("C:/data/results"), true );
253 
254   return true;
255 }
256 
257 
258 //--------------------------------------------------------------
259 template <class T>
compute_both(const vil_image_view<T> & img_tar,const vil_image_view<T> & img_ref,const vil_image_view<bool> & invalid_tar,const vil_image_view<bool> & invalid_ref,int min_disparity,float invalid_disparity,int const & multi_scale_mode,vil_image_view<float> & disp_tar,vil_image_view<float> & disp_ref,float dynamic_range_factor)260 bool bsgm_multiscale_disparity_estimator::compute_both(
261   const vil_image_view<T>& img_tar,
262   const vil_image_view<T>& img_ref,
263   const vil_image_view<bool>& invalid_tar,
264   const vil_image_view<bool>& invalid_ref,
265   int min_disparity,
266   float invalid_disparity,
267   int const& multi_scale_mode,
268   vil_image_view<float>& disp_tar,
269   vil_image_view<float>& disp_ref,
270   float dynamic_range_factor)
271 {
272   // Compute disparity maps for both images
273   compute(img_tar, img_ref, invalid_tar, min_disparity,
274   invalid_disparity, multi_scale_mode, disp_tar, dynamic_range_factor, true);
275   compute(img_ref, img_tar, invalid_ref,
276     (-num_fine_disparities_-min_disparity+1),
277    invalid_disparity, multi_scale_mode, disp_ref, dynamic_range_factor,true);
278 
279   // Compute error maps
280   vil_image_view<bool> error_tar, error_ref;
281   bsgm_check_leftright(disp_tar, disp_ref, invalid_tar, invalid_ref, error_tar);
282   bsgm_check_leftright(disp_ref, disp_tar, invalid_ref, invalid_tar, error_ref);
283 
284   // Set bad pixels to invalid
285   for (size_t y = 0; y < img_tar.nj(); y++)
286     for (size_t x = 0; x < img_tar.ni(); x++)
287       if (error_tar(x, y)) disp_tar(x, y) = invalid_disparity;
288 
289   for (size_t y = 0; y < img_ref.nj(); y++)
290     for (size_t x = 0; x < img_ref.ni(); x++)
291       if (error_ref(x, y)) disp_ref(x, y) = invalid_disparity;
292 
293   // Interpolate
294   if (params_.error_check_mode > 1) {
295     bsgm_interpolate_errors(disp_tar, invalid_tar,
296       img_tar, invalid_disparity, params_.shadow_thresh);
297     bsgm_interpolate_errors(disp_ref, invalid_ref,
298       img_ref, invalid_disparity, params_.shadow_thresh);
299   }
300 
301   return true;
302 }
303 
304 
305 #endif // bsgm_multiscale_disparity_estimator_h_
306