2014-04-12 217 views
11

我已经放在一起的立体摄像机,并且无法使用它产生良好的视差图。这里的两位纠正图像的例子,视差映射我与他们产生:在OpenCV中使用StereoBM的差视差图

Rectified images with disparity map

正如你所看到的,结果是非常糟糕的。改变StereoBM的设置并没有太大的改变。

的设置

  • 这两款相机是相同的模型,并用USB连接到电脑。
  • 它们固定在刚性木板上,使其不会移动。我尽可能地将它们对齐,但当然这并不完美。他们无法移动,所以他们在校准期间和校准后的位置都是一样的。
  • 我使用OpenCV校准了立体对,并使用OpenCV的StereoBM类生成视差图。
  • 这可能不是那么相关,但我使用Python进行编码。

问题我能想象

我这样做的第一次,所以我远不是一个专家,但我猜问题是在校准或立体声整流,而不是视差图的计算。我试过StereoBM的所有设置排列,尽管我得到了不同的结果,但它们都像上面显示的视差图:黑色和白色的补丁。

这个想法得到了进一步支持,据我所知,立体声校正应该对齐每张照片上的所有点,以便它们通过直线(在我的情况下是水平)连接。如果我检查两幅相邻的纠正图片,很明显情况并非如此。右图中的相应点比左边高得多。不过,我不确定校准或校正是否是问题。

代码

实际的代码在物体包裹起来 - 如果你有兴趣看到它的全部,它的可用on GitHub。下面是什么(在真正的代码,我当然校准使用不止2张)实际上是运行一个简单的例子:

import cv2 
import numpy as np 

## Load test images 
# TEST_IMAGES is a list of paths to test images 
input_l, input_r = [cv2.imread(image, cv2.CV_LOAD_IMAGE_GRAYSCALE) 
        for image in TEST_IMAGES] 
image_size = input_l.shape[:2] 

## Retrieve chessboard corners 
# CHESSBOARD_ROWS and CHESSBOARD_COLUMNS are the number of inside rows and 
# columns in the chessboard used for calibration 
pattern_size = CHESSBOARD_ROWS, CHESSBOARD_COLUMNS 
object_points = np.zeros((np.prod(pattern_size), 3), np.float32) 
object_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2) 
# SQUARE_SIZE is the size of the chessboard squares in cm 
object_points *= SQUARE_SIZE 
image_points = {} 
ret, corners_l = cv2.findChessboardCorners(input_l, pattern_size, True) 
cv2.cornerSubPix(input_l, corners_l, 
       (11, 11), (-1, -1), 
       (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS, 
        30, 0.01)) 
image_points["left"] = corners_l.reshape(-1, 2) 
ret, corners_r = cv2.findChessboardCorners(input_r, pattern_size, True) 
cv2.cornerSubPix(input_r, corners_r, 
       (11, 11), (-1, -1), 
       (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS, 
        30, 0.01)) 
image_points["right"] = corners_r.reshape(-1, 2) 

## Calibrate cameras 
(cam_mats, dist_coefs, rect_trans, proj_mats, valid_boxes, 
undistortion_maps, rectification_maps) = {}, {}, {}, {}, {}, {}, {} 
criteria = (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS, 
      100, 1e-5) 
flags = (cv2.CALIB_FIX_ASPECT_RATIO + cv2.CALIB_ZERO_TANGENT_DIST + 
     cv2.CALIB_SAME_FOCAL_LENGTH) 
(ret, cam_mats["left"], dist_coefs["left"], cam_mats["right"], 
dist_coefs["right"], rot_mat, trans_vec, e_mat, 
f_mat) = cv2.stereoCalibrate(object_points, 
           image_points["left"], image_points["right"], 
           image_size, criteria=criteria, flags=flags) 
(rect_trans["left"], rect_trans["right"], 
proj_mats["left"], proj_mats["right"], 
disp_to_depth_mat, valid_boxes["left"], 
valid_boxes["right"]) = cv2.stereoRectify(cam_mats["left"], 
              dist_coefs["left"], 
              cam_mats["right"], 
              dist_coefs["right"], 
              image_size, 
              rot_mat, trans_vec, flags=0) 
for side in ("left", "right"): 
    (undistortion_maps[side], 
    rectification_maps[side]) = cv2.initUndistortRectifyMap(cam_mats[side], 
                  dist_coefs[side], 
                  rect_trans[side], 
                  proj_mats[side], 
                  image_size, 
                  cv2.CV_32FC1) 

## Produce disparity map 
rectified_l = cv2.remap(input_l, undistortion_maps["left"], 
         rectification_maps["left"], 
         cv2.INTER_NEAREST) 
rectified_r = cv2.remap(input_r, undistortion_maps["right"], 
         rectification_maps["right"], 
         cv2.INTER_NEAREST) 
cv2.imshow("left", rectified_l) 
cv2.imshow("right", rectified_r) 
block_matcher = cv2.StereoBM(cv2.STEREO_BM_BASIC_PRESET, 0, 5) 
disp = block_matcher.compute(rectified_l, rectified_r, disptype=cv2.CV_32F) 
cv2.imshow("disparity", disp) 

什么错吗?

回答

13

原来问题是可视化问题,而不是数据本身。在某处我读cv2.reprojectImageTo3D需要差异图作为浮点值,这就是为什么我要求从block_matcher.computecv2.CV_32F

更仔细地阅读OpenCV文档让我认为我错误地认为这是错误的,我实际上喜欢为了速度而使用整数而不是浮点数,但cv2.imshow的文档不清楚关于16位有符号整数(与16位无符号)相比,所以对于可视化我将值作为浮点数来处理。

documentation of cv2.imshow显示32位浮点值被假定为介于0和1之间,所以它们乘以255. 255是一个像素显示为白色的饱和点。在我的情况下,这个假设产生了一个二元图。我手动将其缩小到0-255的范围,然后将它除以255,以抵消OpenCV也一样的事实。我知道,这是一个可怕的行动,但我只是为了调整我的StereoBM下线,所以表现并不重要。解决方案如下所示:

# Other code as above 
disp = block_matcher.compute(rectified_l, rectified_r, disptype=cv2.CV_32F) 
norm_coeff = 255/disp.max() 
cv2.imshow("disparity", disp * norm_coeff/255) 

然后视差图看起来没问题。