Skip to content

Commit 172fdb3

Browse files
committed
Merge pull request #303 from sbokov:improvingStereoSGBM
2 parents 6e4d6bc + 6a0545e commit 172fdb3

File tree

10 files changed

+289
-75
lines changed

10 files changed

+289
-75
lines changed

modules/ximgproc/include/opencv2/ximgproc/disparity_filter.hpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#ifdef __cplusplus
4040

4141
#include <opencv2/core.hpp>
42+
#include <opencv2/calib3d.hpp>
4243

4344
namespace cv {
4445
namespace ximgproc {
@@ -63,15 +64,15 @@ class CV_EXPORTS_W DisparityFilter : public Algorithm
6364
6465
@param filtered_disparity_map output disparity map.
6566
66-
@param ROI region of the disparity map to filter.
67-
6867
@param disparity_map_right optional argument, some implementations might also use the disparity map
6968
of the right view to compute confidence maps, for instance.
7069
70+
@param ROI region of the disparity map to filter. Optional, usually it should be set automatically.
71+
7172
@param right_view optional argument, some implementations might also use the right view of the original
7273
stereo-pair.
7374
*/
74-
CV_WRAP virtual void filter(InputArray disparity_map_left, InputArray left_view, OutputArray filtered_disparity_map, Rect ROI, InputArray disparity_map_right = Mat(), InputArray right_view = Mat()) = 0;
75+
CV_WRAP virtual void filter(InputArray disparity_map_left, InputArray left_view, OutputArray filtered_disparity_map, InputArray disparity_map_right = Mat(), Rect ROI = Rect(), InputArray right_view = Mat()) = 0;
7576
};
7677

7778
/** @brief Disparity map filter based on Weighted Least Squares filter (in form of Fast Global Smoother that
@@ -106,8 +107,7 @@ class CV_EXPORTS_W DisparityWLSFilter : public DisparityFilter
106107
/** @see getLRCthresh */
107108
CV_WRAP virtual void setLRCthresh(int _LRC_thresh) = 0;
108109
/** @brief DepthDiscontinuityRadius is a parameter used in confidence computation. It defines the size of
109-
low-confidence regions around depth discontinuities. For typical window sizes used in stereo matching the
110-
optimal value is around 5.
110+
low-confidence regions around depth discontinuities.
111111
*/
112112
CV_WRAP virtual int getDepthDiscontinuityRadius() = 0;
113113
/** @see getDepthDiscontinuityRadius */
@@ -117,16 +117,36 @@ class CV_EXPORTS_W DisparityWLSFilter : public DisparityFilter
117117
correct disparity values with a high degree of confidence).
118118
*/
119119
CV_WRAP virtual Mat getConfidenceMap() = 0;
120-
120+
/** @brief Get the ROI used in the last filter call
121+
*/
122+
CV_WRAP virtual Rect getROI() = 0;
121123
};
122124

123-
/** @brief Factory method, create instance of DisparityWLSFilter and execute the initialization routines.
125+
/** @brief Convenience factory method that creates an instance of DisparityWLSFilter and sets up all the relevant
126+
filter parameters automatically based on the matcher instance. Currently supports only StereoBM and StereoSGBM.
127+
128+
@param matcher_left stereo matcher instance that will be used with the filter
129+
*/
130+
CV_EXPORTS_W
131+
Ptr<DisparityWLSFilter> createDisparityWLSFilter(Ptr<StereoMatcher> matcher_left);
132+
133+
/** @brief Convenience method to set up the matcher for computing the right-view disparity map
134+
that is required in case of filtering with confidence.
135+
136+
@param matcher_left main stereo matcher instance that will be used with the filter
137+
*/
138+
CV_EXPORTS_W
139+
Ptr<StereoMatcher> createRightMatcher(Ptr<StereoMatcher> matcher_left);
140+
141+
/** @brief More generic factory method, create instance of DisparityWLSFilter and execute basic
142+
initialization routines. When using this method you will need to set-up the ROI, matchers and
143+
other parameters by yourself.
124144
125145
@param use_confidence filtering with confidence requires two disparity maps (for the left and right views) and is
126146
approximately two times slower. However, quality is typically significantly better.
127147
*/
128148
CV_EXPORTS_W
129-
Ptr<DisparityWLSFilter> createDisparityWLSFilter(bool use_confidence);
149+
Ptr<DisparityWLSFilter> createDisparityWLSFilterGeneric(bool use_confidence);
130150

131151
//////////////////////////////////////////////////////////////////////////
132152
//////////////////////////////////////////////////////////////////////////

modules/ximgproc/perf/perf_disparity_wls_filter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ PERF_TEST_P( DisparityWLSFilterPerfTest, perf, Combine(GuideTypes::all(), SrcTyp
8585
cv::setNumThreads(cv::getNumberOfCPUs());
8686
TEST_CYCLE_N(10)
8787
{
88-
Ptr<DisparityWLSFilter> wls_filter = createDisparityWLSFilter(use_conf);
89-
wls_filter->filter(disp_left,guide,dst,ROI,disp_right);
88+
Ptr<DisparityWLSFilter> wls_filter = createDisparityWLSFilterGeneric(use_conf);
89+
wls_filter->filter(disp_left,guide,dst,disp_right,ROI);
9090
}
9191

9292
SANITY_CHECK(dst);

modules/ximgproc/samples/disparity_filtering.cpp

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ const String keys =
2323
"{algorithm |bm | stereo matching method (bm or sgbm) }"
2424
"{filter |wls_conf | used post-filtering (wls_conf or wls_no_conf) }"
2525
"{no-display | | don't display results }"
26-
"{no-downscale | | prevent stereo matching on downscaled views }"
26+
"{no-downscale | | force stereo matching on full-sized views to improve quality }"
2727
"{dst_conf_path |None | optional path to save the confidence map used in filtering }"
2828
"{vis_mult |1.0 | coefficient used to scale disparity map visualizations }"
2929
"{max_disparity |160 | parameter of stereo matching }"
30-
"{window_size |19 | parameter of stereo matching }"
30+
"{window_size |-1 | parameter of stereo matching }"
3131
"{wls_lambda |8000.0 | parameter of post-filtering }"
32-
"{wls_sigma |1.0 | parameter of post-filtering }"
32+
"{wls_sigma |1.5 | parameter of post-filtering }"
3333
;
3434

3535
int main(int argc, char** argv)
@@ -54,17 +54,30 @@ int main(int argc, char** argv)
5454
bool no_display = parser.has("no-display");
5555
bool no_downscale = parser.has("no-downscale");
5656
int max_disp = parser.get<int>("max_disparity");
57-
int wsize = parser.get<int>("window_size");
5857
double lambda = parser.get<double>("wls_lambda");
5958
double sigma = parser.get<double>("wls_sigma");
6059
double vis_mult = parser.get<double>("vis_mult");
6160

61+
int wsize;
62+
if(parser.get<int>("window_size")>=0) //user provided window_size value
63+
wsize = parser.get<int>("window_size");
64+
else
65+
{
66+
if(algo=="sgbm")
67+
wsize = 3; //default window size for SGBM
68+
else if(!no_downscale && algo=="bm" && filter=="wls_conf")
69+
wsize = 7; //default window size for BM on downscaled views (downscaling is performed only for wls_conf)
70+
else
71+
wsize = 15; //default window size for BM on full-sized views
72+
}
73+
6274
if (!parser.check())
6375
{
6476
parser.printErrors();
6577
return -1;
6678
}
6779

80+
//! [load_views]
6881
Mat left = imread(left_im ,IMREAD_COLOR);
6982
if ( left.empty() )
7083
{
@@ -78,6 +91,7 @@ int main(int argc, char** argv)
7891
cout<<"Cannot read image file: "<<right_im;
7992
return -1;
8093
}
94+
//! [load_views]
8195

8296
bool noGT;
8397
Mat GT_disp;
@@ -99,6 +113,7 @@ int main(int argc, char** argv)
99113
Mat conf_map = Mat(left.rows,left.cols,CV_8U);
100114
conf_map = Scalar(255);
101115
Rect ROI;
116+
Ptr<DisparityWLSFilter> wls_filter;
102117
double matching_time, filtering_time;
103118
if(max_disp<=0 || max_disp%16!=0)
104119
{
@@ -110,56 +125,51 @@ int main(int argc, char** argv)
110125
cout<<"Incorrect window_size value: it should be positive and odd";
111126
return -1;
112127
}
113-
if(filter=="wls_conf")
128+
if(filter=="wls_conf") // filtering with confidence (significantly better quality than wls_no_conf)
114129
{
115130
if(!no_downscale)
116131
{
117-
wsize = wsize/2;
118-
if(wsize%2==0) wsize++;
132+
// downscale the views to speed-up the matching stage, as we will need to compute both left
133+
// and right disparity maps for confidence map computation
134+
//! [downscale]
119135
max_disp/=2;
120136
if(max_disp%16!=0)
121137
max_disp += 16-(max_disp%16);
122138
resize(left ,left_for_matcher ,Size(),0.5,0.5);
123139
resize(right,right_for_matcher,Size(),0.5,0.5);
140+
//! [downscale]
124141
}
125142
else
126143
{
127144
left_for_matcher = left.clone();
128145
right_for_matcher = right.clone();
129146
}
130147

131-
132148
if(algo=="bm")
133149
{
134-
Ptr<StereoBM> left_matcher = StereoBM::create(max_disp,wsize);
135-
left_matcher->setMinDisparity(0);
136-
Ptr<StereoBM> right_matcher = StereoBM::create(max_disp,wsize);
137-
right_matcher->setMinDisparity(-max_disp+1);
138-
left_matcher->setTextureThreshold(0);
139-
left_matcher->setUniquenessRatio(0);
140-
right_matcher->setTextureThreshold(0);
141-
right_matcher->setUniquenessRatio(0);
142-
cvtColor(left_for_matcher, left_for_matcher, COLOR_BGR2GRAY);
150+
//! [matching]
151+
Ptr<StereoBM> left_matcher = StereoBM::create(max_disp,wsize);
152+
wls_filter = createDisparityWLSFilter(left_matcher);
153+
Ptr<StereoMatcher> right_matcher = createRightMatcher(left_matcher);
154+
155+
cvtColor(left_for_matcher, left_for_matcher, COLOR_BGR2GRAY);
143156
cvtColor(right_for_matcher, right_for_matcher, COLOR_BGR2GRAY);
144-
ROI = computeROI(left_for_matcher.size(),left_matcher);
145157

146158
matching_time = (double)getTickCount();
147159
left_matcher-> compute(left_for_matcher, right_for_matcher,left_disp);
148160
right_matcher->compute(right_for_matcher,left_for_matcher, right_disp);
149161
matching_time = ((double)getTickCount() - matching_time)/getTickFrequency();
162+
//! [matching]
150163
}
151164
else if(algo=="sgbm")
152165
{
153166
Ptr<StereoSGBM> left_matcher = StereoSGBM::create(0,max_disp,wsize);
154-
left_matcher->setMinDisparity(0);
155-
Ptr<StereoSGBM> right_matcher = StereoSGBM::create(-max_disp+1,max_disp,wsize);
156-
left_matcher->setUniquenessRatio(0);
157-
left_matcher->setDisp12MaxDiff(1000000);
158-
left_matcher->setSpeckleWindowSize(0);
159-
right_matcher->setUniquenessRatio(0);
160-
right_matcher->setDisp12MaxDiff(1000000);
161-
right_matcher->setSpeckleWindowSize(0);
162-
ROI = computeROI(left_for_matcher.size(),left_matcher);
167+
left_matcher->setP1(24*wsize*wsize);
168+
left_matcher->setP2(96*wsize*wsize);
169+
left_matcher->setPreFilterCap(63);
170+
left_matcher->setMode(StereoSGBM::MODE_SGBM_3WAY);
171+
wls_filter = createDisparityWLSFilter(left_matcher);
172+
Ptr<StereoMatcher> right_matcher = createRightMatcher(left_matcher);
163173

164174
matching_time = (double)getTickCount();
165175
left_matcher-> compute(left_for_matcher, right_for_matcher,left_disp);
@@ -172,14 +182,17 @@ int main(int argc, char** argv)
172182
return -1;
173183
}
174184

175-
Ptr<DisparityWLSFilter> wls_filter = createDisparityWLSFilter(true);
185+
//! [filtering]
176186
wls_filter->setLambda(lambda);
177187
wls_filter->setSigmaColor(sigma);
178188
filtering_time = (double)getTickCount();
179-
wls_filter->filter(left_disp,left,filtered_disp,ROI,right_disp);
189+
wls_filter->filter(left_disp,left,filtered_disp,right_disp);
180190
filtering_time = ((double)getTickCount() - filtering_time)/getTickFrequency();
191+
//! [filtering]
181192
conf_map = wls_filter->getConfidenceMap();
182193

194+
// Get the ROI that was used in the last filter call:
195+
ROI = wls_filter->getROI();
183196
if(!no_downscale)
184197
{
185198
// upscale raw disparity and ROI back for a proper comparison:
@@ -190,6 +203,9 @@ int main(int argc, char** argv)
190203
}
191204
else if(filter=="wls_no_conf")
192205
{
206+
/* There is no convenience function for the case of filtering with no confidence, so we
207+
will need to set the ROI and matcher parameters manually */
208+
193209
left_for_matcher = left.clone();
194210
right_for_matcher = right.clone();
195211

@@ -201,6 +217,8 @@ int main(int argc, char** argv)
201217
cvtColor(left_for_matcher, left_for_matcher, COLOR_BGR2GRAY);
202218
cvtColor(right_for_matcher, right_for_matcher, COLOR_BGR2GRAY);
203219
ROI = computeROI(left_for_matcher.size(),matcher);
220+
wls_filter = createDisparityWLSFilterGeneric(false);
221+
wls_filter->setDepthDiscontinuityRadius((int)ceil(0.33*wsize));
204222

205223
matching_time = (double)getTickCount();
206224
matcher->compute(left_for_matcher,right_for_matcher,left_disp);
@@ -212,7 +230,12 @@ int main(int argc, char** argv)
212230
matcher->setUniquenessRatio(0);
213231
matcher->setDisp12MaxDiff(1000000);
214232
matcher->setSpeckleWindowSize(0);
233+
matcher->setP1(24*wsize*wsize);
234+
matcher->setP2(96*wsize*wsize);
235+
matcher->setMode(StereoSGBM::MODE_SGBM_3WAY);
215236
ROI = computeROI(left_for_matcher.size(),matcher);
237+
wls_filter = createDisparityWLSFilterGeneric(false);
238+
wls_filter->setDepthDiscontinuityRadius((int)ceil(0.5*wsize));
216239

217240
matching_time = (double)getTickCount();
218241
matcher->compute(left_for_matcher,right_for_matcher,left_disp);
@@ -224,11 +247,10 @@ int main(int argc, char** argv)
224247
return -1;
225248
}
226249

227-
Ptr<DisparityWLSFilter> wls_filter = createDisparityWLSFilter(false);
228250
wls_filter->setLambda(lambda);
229251
wls_filter->setSigmaColor(sigma);
230252
filtering_time = (double)getTickCount();
231-
wls_filter->filter(left_disp,left,filtered_disp,ROI);
253+
wls_filter->filter(left_disp,left,filtered_disp,Mat(),ROI);
232254
filtering_time = ((double)getTickCount() - filtering_time)/getTickFrequency();
233255
}
234256
else
@@ -292,6 +314,7 @@ int main(int argc, char** argv)
292314
imshow("ground-truth disparity", GT_disp_vis);
293315
}
294316

317+
//! [visualization]
295318
Mat raw_disp_vis;
296319
getDisparityVis(left_disp,raw_disp_vis,vis_mult);
297320
namedWindow("raw disparity", WINDOW_AUTOSIZE);
@@ -301,6 +324,7 @@ int main(int argc, char** argv)
301324
namedWindow("filtered disparity", WINDOW_AUTOSIZE);
302325
imshow("filtered disparity", filtered_disp_vis);
303326
waitKey();
327+
//! [visualization]
304328
}
305329

306330
return 0;

0 commit comments

Comments
 (0)