Getting a reasonable disparity map

Hello, I am trying to create a disparity map using a pair of undistorted and rectified images. Inspecting the images, they are vertically aligned, but the disparity map looks terrible no matter what parameters I choose. I used a BM tuning project to attempt to play with the parameters while looking at the results on the fly, and nothing I tried looks close to reasonable. I’m including the pair of left and right images, and the very simple code I use to get the basic disparity map (the tuner I used is located here). Is something wrong with my images? Is there anything i can do to get a decent disparity map? Thanks in advance.

import numpy as np
import cv2
from matplotlib import pyplot as plt

imgL = cv2.imread('ImageL.png',0)
imgR = cv2.imread('ImageR.png',0)

stereo = cv2.StereoSGBM_create(numDisparities=16, blockSize=13)
disparity = stereo.compute(imgL,imgR)
plt.imshow(disparity,'gray')
plt.show()

that’s not much. go higher. also check what you have for mindisparity (or whatever that was). you can see how many pixels of disparity those nearby objects have.

I tried cranking numDisparities as high as several hundred. I can see the outlines of objects but it’s far from ideal. As far as minDispaities, I dragged the values from 0 to the max using that tuner I mentioned, without getting a good result. The table for example is usually very bright, while the battery and the rectangular block are darker, even though they are closer to the cameras than some of the table pixels. In general, it seems more noise than depth map.

don’t expect any sensible results on smooth parts of the images. this stuff need structure/texture/gradient/contrast to latch onto.

larger block size should help somewhat. 13 should be getting you some results tho.

oh, also try switching the pictures as arguments, left/right, right/left. maybe it’s wanting the other way.

Thanks for the advice. I tried every combination I could reasonably manage, and the results are unusable with both stereoBM and stereoSGBM. I also tried switching the pictures, and got no improvement, although I’ve triple checked that I have left and right set correctly. I’ll try again with something textured.

you’re gonna need minDisparity+numDisparities to be upto 200, unless I remember this API wrong. the duracell needs ~130-140, the edge of the table something like 190, the “otium” around 120, and the stuff in the background around 60-90.

set minDisparity to 0 and numDisparities to 150 for a start.

then you’ll want to play with the other parameters. especially P1 and P2 make a lot of difference, if you set them according to the documentation (and then tweak), rather than keeping them default (0).

here’s some quick and dirty script to play with. you can extend it to work with all the other parameters.

#!/usr/bin/env python3

import os
import sys
import numpy as np
import cv2 as cv; cv2 = cv

imgL = cv2.imread('left.jpg', 0)
imgR = cv2.imread('right.jpg', 0)


blockSize = 11
min_disparity = 50
max_disparity = 150
P1 = 8
P2 = 32

stereo = cv2.StereoSGBM_create(
	minDisparity=min_disparity,
	numDisparities=(max_disparity - min_disparity),
	blockSize=blockSize,
	P1=3*blockSize*blockSize * P1,
	P2=3*blockSize*blockSize * P2,
	disp12MaxDiff=0,
	preFilterCap=0,
	uniquenessRatio=10,
#	speckleWindowSize=100,
#	speckleRange=1,
#	mode=cv.StereoSGBM_MODE_SGBM
#	#mode=cv.StereoSGBM_MODE_HH
)

def redraw():
	disparity = stereo.compute(imgL,imgR)

	out = (disparity / np.float32(16)) / max_disparity

	#disparity = stereo.compute(imgR,imgL)

	cv.imshow("out", out)


def on_blockSize(pos):
	global blockSize
	blockSize = 1 - (1 - pos) // 2 * 2
	stereo.setBlockSize(blockSize)
	redraw()

def on_mindisparity(pos):
	global min_disparity
	min_disparity = pos
	stereo.setMinDisparity(min_disparity)
	stereo.setNumDisparities(max_disparity - min_disparity)
	redraw()

def on_maxdisparity(pos):
	global max_disparity
	max_disparity = pos
	stereo.setNumDisparities(max_disparity - min_disparity)
	redraw()

def on_P1(pos):
	global P1
	P1 = pos
	stereo.setP1(3*blockSize*blockSize * P1)
	redraw()

def on_P2(pos):
	global P2
	P2 = pos
	stereo.setP2(3*blockSize*blockSize * P2)
	redraw()

def set_disp12MaxDiff(pos):
	stereo.setDisp12MaxDiff(pos)
	redraw()

def set_preFilterCap(pos):
	stereo.setPreFilterCap(pos)
	redraw()


cv.namedWindow("out")
cv.createTrackbar("blockSize", "out", blockSize, 51, on_blockSize)
cv.createTrackbar("minDisparity", "out", min_disparity, 200, on_mindisparity)
cv.createTrackbar("maxDisparity", "out", max_disparity, 200, on_maxdisparity)
cv.createTrackbar("P1", "out", P1, 64, on_P1)
cv.createTrackbar("P2", "out", P2, 64, on_P2)
cv.createTrackbar("disp12MaxDiff", "out", 0, 100, set_disp12MaxDiff)
cv.createTrackbar("preFilterCap", "out", 0, 100, set_preFilterCap)



redraw()
while True:
	key = cv.waitKey()
	if key == -1:
		break
	print(key)