Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pre/Post Processing Steps for Further Disparity improvements #20

Open
mohanen opened this issue Sep 15, 2018 · 16 comments
Open

Pre/Post Processing Steps for Further Disparity improvements #20

mohanen opened this issue Sep 15, 2018 · 16 comments

Comments

@mohanen
Copy link

mohanen commented Sep 15, 2018

The Disparity from libSGM, when projected in a point cloud the output contains noise like a pyramid in front of the camera covering the entire scene or the edges of the of the object seem to replicate multiple times in various disparity levels.

screenshot from 2018-09-15 07-41-04
screenshot from 2018-09-15 07-39-28

I have some knowledge on how sgm works and for post-processing I have been looking into Nerian's post-processing Steps and Hirshmullers Disparity Refinement Steps to improve the disparity map.

I was able to remove the noise (mentioned above) using a speckle filter which retained the correct data but at the cost of making it sparse almost losing more than 50% of the data in some scenes.

screenshot from 2018-09-15 07-40-45
screenshot from 2018-09-15 07-40-30

And looking at the other post-processing steps like Uniqueness check, Consistency check, Filtering of untextured image areas, Noise reduction seems to make the disparity even sparser and applying an optimal hole/gap filling technique wouldn't be enough I think.

I know SGM can do it better it even won 11th place in the ROB 2018.

So do you guys have any idea on

  1. How can I improve the disparity accuracy without making it sparse, what are the Pre/Post processing steps can be implemented to further improve it?
  2. How to include sub-pixel accuracy, any plans on including it?

Thanks and Regards,
Mohanen B

@atakagi-fixstars
Copy link
Contributor

atakagi-fixstars commented Sep 18, 2018

Hi, Mohanen

Thank you for your contribution.
I answer your questions.

1. Pre/Post processing

We have heard about Disparity map post-filtering which we can use from OpenCV.
https://docs.opencv.org/3.3.0/d3/d14/tutorial_ximgproc_disparity_filtering.html

We are going to apply this method to libSGM and evaluate it's ability.

2. Including sub-pixel accuracy

We are willing to implement sub-pixel interpolation, maybe it will lead to some performance loss however.

Regards,

@mohanen
Copy link
Author

mohanen commented Sep 18, 2018

Hi, @atakagi-fixstars,

In your latest code, the pyramid-like noise mentioned above is almost gone but still some noise exist, I was using an older commit before.

I already tried the WLS filter.

  • doesn't do well on the edges,
  • doesn't fill the occlusion hole and
  • again produces the pyramid-like noise.

I was using WLS with Confidence off and lambda and sigma values as preferred by OpenCV documentation.

Note: This same issue occurred for OpenCV SGBM (confidence on) too.

libSGM output
screenshot from 2018-09-18 12-46-48
screenshot from 2018-09-18 12-47-22

WLS applied
screenshot from 2018-09-18 12-48-59
screenshot from 2018-09-18 12-49-19

@atakagi-fixstars
Copy link
Contributor

atakagi-fixstars commented Sep 18, 2018

Hi, @mohanen

Thank you for your work!
The WLS doesn't perform well... so we must find another way.

@0Jiahao
Copy link

0Jiahao commented Jun 12, 2019

Hi @mohanen, I am having the same pyramid result as the one in your first comment. Could you please share the method for removing it?

Kind regards,
Jiahao

@mohanen
Copy link
Author

mohanen commented Jun 13, 2019

If you are upscaling the disparity map means use nearest neighbor interpolation.

@0Jiahao
Copy link

0Jiahao commented Jun 17, 2019

@mohanen Thank you for your reply! Could you please give me an example or a link of which code I could refer to?

@lingjiankong
Copy link

lingjiankong commented Aug 28, 2019

For those who are wondering how to use OpenCV DisparityWLSFilter:

The trick is that you would need the negate the right disparity when passing it to DisparityWLSFilter::filter.

Below is an example:

// To calculate right disparaity, you need to flip the images and then flip the disparity back.
cv::Mat rightDisparity(right.size(), CV_16S);
cv::Mat flippedRightDisparity(right.size(), CV_16S);

cv::Mat flippedLeft(left.size(), CV_8U);
cv::Mat flippedRight(right.size(), CV_8U);

cv::flip(left, flippedLeft, 1);
cv::flip(right, flippedRight, 1);

sgm::StereoSGM ssgm_right(left.cols, left.rows, disp_size, input_depth, output_depth, sgm::EXECUTE_INOUT_HOST2HOST, param);
ssgm_right.execute(flippedRight.data, flippedLeft.data, flippedRightDisparity.data);

flip(flippedRightDisparity, rightDisparity, 1);

// OpenCV's DisparityWLSFilter implicitly assumes that the disparity is 16SC1 format
// and has been scaled up by 16 (yeah this part is very confusing).
// Therefore, for right disparity, you need to multiply by 16, and negate it (hence -16).

rightDisparity *= -16;

...

// Now you can call OpenCV's DisparityWLSFilter to give you a decent filtered disparity:
Ptr<DisparityWLSFilter> wlfFilter = createDisparityWLSFilterGeneric(true);
cv::Mat filteredDisp;

...

wlsFilter ->filter(disparity, left, filteredDisp, rightDisparity);

@mohanen
Copy link
Author

mohanen commented Aug 28, 2019

// OpenCV's DisparityWLSFilter implicitly assumes that the disparity is 16SC1 format
// and has been scaled up by 16 (yeah this part is very confusing).
// Therefore, for right disparity, you need to multiply by 16, and negate it (hence -16).

@lingjiankong The 16 is due to the fact that its a fixed point representation fixed<16,4> and requires conversion to float to be used.

fixed<16,4> denotes a 16-bit fixed-point number, of which 4 rightmost bits are fractional.

To convert that, perceive the bit string as an integer and divide it with 2 power number of bits used for the fraction part. 2^4 = 16.

@sotsuka-fixstars
Copy link
Contributor

sotsuka-fixstars commented Aug 29, 2019

@lingjiankong Thank you for your work!

If we shared param with left matcher (or we shared sgm::StereoSGM instance as left and right matcher),
it is not needed to multiply 16 as sub pixel scale.

- rightDisparity *= -16;
+ rightDisparity *= -1;
disc image
input input
libSGM libSGM_disparity_color
libSGM(4PATH, w/ subpixel)+WLS filtered_disparity_color
libSGM(4PATH, w/o subpixel)+WLS libSGM_disparity_color_without_subpixel

@funmonty
Copy link

@sotsuka-fixstars Great results. The WLS filter looks surprisingly promising. Can you share any pointclouds of your version of WLS filter? Does it have the same pyramid effect that @mohanen has described in this thread?

@sotsuka-fixstars
Copy link
Contributor

sotsuka-fixstars commented Aug 30, 2019

@funmonty
I thought so at a first glance.
However, WLS Filter does not work fine in KITTI benchmark at our experience.
@8BitCatJQW made another point cloud application using libSGM. It may help you.

https://github.com/8BitCatJQW/libsgmIssueDetails

I modified it, earned following outputs by using different filter.

filter KITTI stereo 2015 000006_10 Middlebury 2006 Baby
None snapshot00_L00 snapshot01_L00
WLS snapshot00_L01 snapshot01_L01
Bilateral snapshot00_L02 snapshot01_L02

@mohanen
Copy link
Author

mohanen commented Aug 30, 2019

@sotsuka-fixstars, Can you share the filter code snippets.

@sotsuka-fixstars
Copy link
Contributor

@mohanen Is a following snippet an answer to the request?

// WLS
cv::Ptr<cv::ximgproc::DisparityWLSFilter> wls_f = cv::ximgproc::createDisparityWLSFilterGeneric(true);
cv::Mat wls_filtered_disp;
wls_f->filter(disparity, I1, wls_filtered_disp, disp_right);

// Bilateral
cv::cuda::GpuMat g_disp, g_filtered_disp;
g_disp.upload(disparity);
cv::cuda::bilateralFilter(g_disp, g_filtered_disp, kernel_size, sigma_color, sigma_spatial);
cv::Mat bilateral_filtered_disp;
g_filtered_disp.download(bilateral_filtered_disp);

kernel_size, sigma_color, sigma_spatial come from command line argument.
I decided these params slackly because I didn't know proper values of these...

@ynma-hanvo
Copy link

is this implementation the cuda version of opencv StereoSGBM?
i found the result of the two is different. there is a blocksize parameter in StereoSGBM, which i cann't found here.
thanks for the explanation!

@atakagi-fixstars
Copy link
Contributor

Hi, @ynma-hanvo

is this implementation the cuda version of opencv StereoSGBM?

No.
In libSGM, 9x7 center-symmetric census transform is used for matching cost.

@mcelhennyi
Copy link

mcelhennyi commented Jul 13, 2021

@mohanen Is a following snippet an answer to the request?

// WLS
cv::Ptr<cv::ximgproc::DisparityWLSFilter> wls_f = cv::ximgproc::createDisparityWLSFilterGeneric(true);
cv::Mat wls_filtered_disp;
wls_f->filter(disparity, I1, wls_filtered_disp, disp_right);

// Bilateral
cv::cuda::GpuMat g_disp, g_filtered_disp;
g_disp.upload(disparity);
cv::cuda::bilateralFilter(g_disp, g_filtered_disp, kernel_size, sigma_color, sigma_spatial);
cv::Mat bilateral_filtered_disp;
g_filtered_disp.download(bilateral_filtered_disp);

kernel_size, sigma_color, sigma_spatial come from command line argument.
I decided these params slackly because I didn't know proper values of these...

Does the bilateral filter work in subpixel mode? Do we need to filter off the invalid pixels first for better or accurate filtering?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants