【问题标题】:How to improve depth map and what are my stereo images lacking?如何改善深度图以及我的立体图像缺少什么?
【发布时间】:2019-07-24 17:35:51
【问题描述】:

我一直在尝试使用 opencv 将立体图像转换为深度图,但无论我做什么,它似乎都无法读取。

我能够获得 opencv 教程中提供的示例图像的准确深度图像,但在任何其他图像上都没有。即使我尝试从网上下载其他预制的、校准过的立体图像,我也得到了既不准确也不接近示例图像质量的糟糕结果。

这是我用来制作深度图的主要 Python 脚本:

import numpy as np
import cv2
from matplotlib import pyplot as plt
imgL = cv2.imread('calimg_L.png',0)
imgR = cv2.imread('calimg_R.png',0)
# imgL = cv2.imread('./images/example_L.png',0)
# imgR = cv2.imread('./images/example_R.png',0)
stereo = cv2.StereoSGBM_create(numDisparities=16, blockSize=15)
disparity = stereo.compute(imgR,imgL)
norm_image = cv2.normalize(disparity, None, alpha = 0, beta = 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)
cv2.imwrite("disparityImage.jpg", norm_image)
plt.imshow(norm_image)
plt.show()

其中 calimg_L.png 是原始图像的校准版本。

这是我用来校准图像的代码:

import numpy as np
import cv2
import glob

from matplotlib import pyplot as plt
def createCalibratedImage(inputImage, outputName):
    # termination criteria
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

    # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
    objp = np.zeros((3*3,3), np.float32)
    objp[:,:2] = np.mgrid[0:3,0:3].T.reshape(-1,2)

    # Arrays to store object points and image points from all the images.
    objpoints = [] # 3d point in real world space
    imgpoints = [] # 2d points in image plane.
    # org = cv2.imread('./chess.jpg')
    # orig_cal_img = cv2.resize(org, (384, 288))
    # cv2.imwrite("cal_chess.jpg", orig_cal_img)

    images = glob.glob('./chess_webcam/*.jpg')

    for fname in images:
        print('file in use: ' + fname)
        img = cv2.imread(fname)
        gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

        # Find the chess board corners
        ret, corners = cv2.findChessboardCorners(gray, (3,3),None)

        # print("doing the thing");
        print('status: ' + str(ret));
        # If found, add object points, image points (after refining them)
        if ret == True:
            # print("found something");
            objpoints.append(objp)

            cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
            imgpoints.append(corners)

            # Draw and display the corners
            cv2.drawChessboardCorners(img, (3,3), corners,ret)
            cv2.imshow('img',img)
            cv2.waitKey(500)
            ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
            img = inputImage
            h,  w = img.shape[:2]
            newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
    # undistort
    print('undistorting...')
    mapx,mapy = cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)
    dst = cv2.remap(inputImage ,mapx,mapy,cv2.INTER_LINEAR)
    # crop the image
    x,y,w,h = roi
    dst = dst[y:y+h, x:x+w]
    # cv2.imwrite('calibresult.png',dst)
    cv2.imwrite(outputName + '.png',dst)
    cv2.destroyAllWindows()


original_L = cv2.imread('capture_L.jpg')
original_R = cv2.imread('capture_R.jpg')
createCalibratedImage(original_R, "calimg_R")
createCalibratedImage(original_L, "calimg_L")
print("images calibrated and outputed")

此代码取自 opencv tutorial on how to calibrate images 并提供了至少 16 个棋盘图像,但只能识别其中大约 4 - 5 个棋盘。我使用相对较小的 3x3 网格搜索的原因是,由于无法找到棋盘,任何更高的东西都让我没有任何图像可用于校准。

这是我从示例图片中得到的(抱歉,奇怪的链接,找不到如何上传): https://ibb.co/DYMcdZc

这是原文: https://ibb.co/gMkqyXD https://ibb.co/YQZY40C

这是应该的,但是当我将它与任何其他图像一起使用时,它会让我一团糟,例如:

输出: https://ibb.co/kXwgDVn

看起来只是一堆像素,公平地说,当您在 imshow 上将其设置为“灰色”时,它看起来更具可读性,但它并不能很好地代表图像的深度,以下是原件: https://ibb.co/vqDKGS0 https://ibb.co/f0X1gMB

更糟糕的是,当我自己拍摄图像并通过棋盘代码校准它们时,它会显示为白色和黑色像素的随机混乱,一些像素的值变成负数,而一些像素的值高得不可思议。

tl;dr 即使示例图像工作正常,我也无法将任何立体图像制作成深度图,这是为什么呢?

【问题讨论】:

    标签: python opencv stereoscopy


    【解决方案1】:

    首先我想说,获得一张好的深度图并不是一件容易的事,使用基本的 StereoMatching 并不总是能带来好的结果。尽管如此,还是可以取得更好的成绩。

    按顺序:

    • 校准:你应该可以在更多的图像中找到棋盘格,4/5对于校准来说是一个非常低的数字,如此低的数字很难正确估计相机参数。图像看起来如何?您是否将它们视为灰度图像?通常也为行和列使用不同的数字(不是 3x3 网格,如 4x3)有助于理解棋盘的位置(否则可能会混淆哪一边是向上或向右,例如,90 度旋转将导致 0 旋转)。
    • 纠正:这可以通过查看图像轻松检查。打开两个不同图层上的两个图像(使用 GIMP 或类似方法)并检查相似点。校正图像后,它们应该位于同一条线上。他们真的在同一条线上吗?如果是,则纠正工作,否则,您需要更好的校准。没有这一步,立体匹配将无法工作。
    • 立体匹配:如果以上步骤都正确,那么立体匹配的参数可能有问题。首先要检查的是视差范围(因为看起来示例图像和图像之间的分辨率不同,您应该检查并调整该值)。最小视差也可以提供帮助(如果您减小视差范围,则可以减少错误的可能性)以及块大小(15 相当大,更小也足够了)。

    根据您的说法,我猜问题出在校准上。您应该尝试检查校正后的图像,如果存在问题,请尝试获取新数据集(或在网上找到更好的数据集)并在那里校准您的图像。一旦您可以正确校准和校正图像,您应该会获得更好的结果。 我看到代码类似于教程here,所以我想这是正确的,主要问题是图像。希望对您有所帮助,如果您测试并查看问题所在的位置,我可以为您提供更多帮助!

    【讨论】:

    • 您好,我知道图片必须垂直对齐,但我认为会有轻微的误差?它应该有多准确/
    • 两个匹配项(例如使用一个角)应该完全相同的高度。理论上,立体匹配假设两个对应点(也就是两个匹配点)位于同一个epipolar line 上。这意味着,对对应的搜索仅沿一个方向进行(否则它的计算成本会太高)。所以它们应该对齐,可能最多一个像素。如果您的像素误差 > 2-3 像素,那么您的深度图很可能是嘈杂的。很难有一个固定的阈值(这取决于很多事情)!
    猜你喜欢
    • 2020-09-30
    • 2015-02-27
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 2011-08-07
    • 1970-01-01
    • 2012-04-23
    相关资源
    最近更新 更多