When using StereoBM, as the minimum disparities values is increased, the right side of the resulting disparity map is truncated by a corresponding pixel count. The actual calculated disparity has been correctly calculated, but getValidDisparityROI has truncated the right side of the disparity map. StereoSGBM does not similarly truncate the right side of the disparity map.
I've observed this behavior on OpenCV master (as of 01-Oct-2017) and the 2.4.8+dfsg1 as packaged with Ubuntu 14.04 on amd64 and armhf.
Example: Input left and right images are the data/aloeL.jpg and data/aloeR.jpg used by the samples/python/stereo_match.py example.
Left image is:
Disparity image at min disparities = 0 (this is expected) has the expected features: a left margin that is minDisparities + numberOfDisparities wide, and top, bottom and right margins of half the block match window width (17 / 2 = 8). Here is the disparity image at min disparities = 0:
The disparity image at min disparities = 32 shows both left and right side margin expanded by min disparities. The expanded right margin is my concern:
Possible solution: If the line from getValidDisparityROI (from modules/calib3d/src/stereosgbm.cpp) which reads:
int xmax = std::min(roi1.x + roi1.width, roi2.x + roi2.width - minD) - SW2;
it is instead calculated thusly:
int xmax = std::min(roi1.x + roi1.width, roi2.x + roi2.width) - SW2;
Then the output disparity map is correctly calculated, without truncation on the right side:
Discussion: I'm suspecting this is a bug that only affects StereoBM. Like StereoBM, StereoSGBM calculates correct disparity data to the right edge disparity image, but StereoSGBM does not truncate the right side.
My application needs the speed of StereoBM, and my cameras are relatively widely spaced for a relatively near target, meaning I'm expecting disparities of 100-250 on an image only ~1000 pixels wide - lopping off an extra minDisparity = 100 pixels on the right side is quite a sacrifice.
Question: Check my reasoning/assertions. Shall I file this as a bug and propose the above getValidDisparityROI modification as a fix? Is there a better or more correct fix?
Appendix: My Calculation/display code is:
#!/usr/bin/env python
# Python 2/3 compatibility
from __future__ import print_function
import sys
import numpy as np
import cv2
print('load and downscale images')
imgL = cv2.pyrDown( cv2.imread('../data/aloeL.jpg') )
imgR = cv2.pyrDown( cv2.imread('../data/aloeR.jpg') )
min_disp = 16
num_disp = 112 - min_disp
if sys.argv[1] > 0:
min_disp = int(sys.argv[1])
window_size = 17
stereo = cv2.StereoBM_create(numDisparities = num_disp, blockSize = window_size)
stereo.setMinDisparity(min_disp)
stereo.setNumDisparities(num_disp)
stereo.setBlockSize(window_size)
stereo.setDisp12MaxDiff(0)
stereo.setUniquenessRatio(10)
stereo.setSpeckleRange(32)
stereo.setSpeckleWindowSize(100)
print('compute disparity')
grayL = cv2.cvtColor(imgL, cv2.COLOR_BGR2GRAY)
grayR = cv2.cvtColor(imgR, cv2.COLOR_BGR2GRAY)
disp = stereo.compute(grayL, grayR).astype(np.float32) / 16.0
disp_map = (disp - min_disp)/num_disp
print('display')
cv2.imshow('left', imgL)
cv2.imshow('disparity', disp_map)
cv2.waitKey()
cv2.destroyAllWindows()