【问题标题】:Bad disparity map using StereoBM in OpenCV在 OpenCV 中使用 StereoBM 的视差图不好
【发布时间】:2014-05-26 16:22:40
【问题描述】:

我已经组装了一个立体摄像装置,但在使用它来生成良好的视差图时遇到了麻烦。这是两个校正图像的示例以及我用它们制作的视差图:

如您所见,结果非常糟糕。更改 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)

这里出了什么问题?

【问题讨论】:

    标签: python opencv computer-vision stereo-3d


    【解决方案1】:

    原来问题出在可视化而不是数据本身。在某处我读到cv2.reprojectImageTo3D 需要一个视差图作为浮点值,这就是我从block_matcher.compute 请求cv2.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)
    

    那么视差图看起来还不错。

    【讨论】:

    • 我得到这个错误:TypeError: 'disptype' is an invalid keyword argument for StereoMatcher.compute()
    猜你喜欢
    • 2016-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 2018-10-02
    • 2013-12-19
    • 2018-08-01
    • 2014-07-18
    相关资源
    最近更新 更多