如何改进深度图以及我的立体图像缺少什么?
How to improve depth map and what are my stereo images lacking?
我一直在尝试使用 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 教程,并提供了至少 16 张棋盘图像,但只能识别其中大约 4 - 5 张棋盘。我使用相对较小的 3x3 网格搜索的原因是,由于无法找到棋盘,更高的位置让我没有任何图像可用于校准。
这是我从示例图片中得到的(很抱歉 link,找不到如何上传):
https://ibb.co/DYMcdZc
原文如下:
https://ibb.co/gMkqyXD
https://ibb.co/YQZY40C
这是它应该的行为,但是当我将它与任何其他图像一起使用时,它会给我带来麻烦,例如:
看起来只是一堆像素,公平地说,当你把它放到 'gray' 上 imshow 时,它看起来更具可读性,但它并不能很好地代表图像的深度,这是原件:
https://ibb.co/vqDKGS0
https://ibb.co/f0X1gMB
更糟糕的是,当我自己拍摄图像并通过棋盘代码对它们进行校准时,结果只是一堆随机的白色和黑色像素,一些像素的值变成负数,一些像素高得离谱价值。
tl;dr 我无法将任何立体图像制作成深度图,即使示例图像工作得很好,这是为什么?
首先我想说的是,获得一个好的深度图并不是一件简单的事情,使用基本的StereoMatching也不一定总能得到好的结果。尽管如此,还是可以取得更好的成绩。
依次为:
- 标定:你应该可以在更多图像中找到棋盘格,4/5 是一个非常低的标定数字,如此低的数字很难正确估计相机参数。图像看起来如何?你把它们读成灰度图像了吗?通常还对行和列使用不同的数字(不是 3x3 网格,如 4x3)有助于理解棋盘位置(否则可能会不清楚哪一侧在上或在右,例如,90 度旋转将导致 0 度旋转)。
- 纠正:这可以通过查看图像轻松检查。打开两个不同层上的两个图像(使用 GIMP 或类似工具)并检查相似点。校正图像后,它们应该位于同一条线上。他们真的在同一条线上吗?如果是,则进行整改,否则,您需要进行更好的校准。没有这一步,立体匹配将无法工作。
- 立体匹配:如果以上步骤都正确,那么可能是立体匹配的参数有问题。首先要检查的是视差范围(因为看起来示例图像和您的图像之间的分辨率不同,您应该检查并调整该值)。最小差异也有帮助(如果减小差异范围,则可以减少错误的可能性)和块大小(15 很大,较小也足够)。
根据你的说法,我的猜测是校准有问题。您应该尝试检查校正后的图像,如果存在问题,请尝试获取新的数据集(或在网上找到更好的数据集)并在那里校准您的图像。一旦你可以正确地校准和校正你的图像,你应该会得到更好的结果。
我看到代码类似于教程 here,所以我想这是正确的,主要问题是图像。希望对你有帮助,如果你测试看看问题出在哪里,我可以帮助你更多!
我一直在尝试使用 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 教程,并提供了至少 16 张棋盘图像,但只能识别其中大约 4 - 5 张棋盘。我使用相对较小的 3x3 网格搜索的原因是,由于无法找到棋盘,更高的位置让我没有任何图像可用于校准。
这是我从示例图片中得到的(很抱歉 link,找不到如何上传): https://ibb.co/DYMcdZc
原文如下: https://ibb.co/gMkqyXD https://ibb.co/YQZY40C
这是它应该的行为,但是当我将它与任何其他图像一起使用时,它会给我带来麻烦,例如:
看起来只是一堆像素,公平地说,当你把它放到 'gray' 上 imshow 时,它看起来更具可读性,但它并不能很好地代表图像的深度,这是原件: https://ibb.co/vqDKGS0 https://ibb.co/f0X1gMB
更糟糕的是,当我自己拍摄图像并通过棋盘代码对它们进行校准时,结果只是一堆随机的白色和黑色像素,一些像素的值变成负数,一些像素高得离谱价值。
tl;dr 我无法将任何立体图像制作成深度图,即使示例图像工作得很好,这是为什么?
首先我想说的是,获得一个好的深度图并不是一件简单的事情,使用基本的StereoMatching也不一定总能得到好的结果。尽管如此,还是可以取得更好的成绩。
依次为:
- 标定:你应该可以在更多图像中找到棋盘格,4/5 是一个非常低的标定数字,如此低的数字很难正确估计相机参数。图像看起来如何?你把它们读成灰度图像了吗?通常还对行和列使用不同的数字(不是 3x3 网格,如 4x3)有助于理解棋盘位置(否则可能会不清楚哪一侧在上或在右,例如,90 度旋转将导致 0 度旋转)。
- 纠正:这可以通过查看图像轻松检查。打开两个不同层上的两个图像(使用 GIMP 或类似工具)并检查相似点。校正图像后,它们应该位于同一条线上。他们真的在同一条线上吗?如果是,则进行整改,否则,您需要进行更好的校准。没有这一步,立体匹配将无法工作。
- 立体匹配:如果以上步骤都正确,那么可能是立体匹配的参数有问题。首先要检查的是视差范围(因为看起来示例图像和您的图像之间的分辨率不同,您应该检查并调整该值)。最小差异也有帮助(如果减小差异范围,则可以减少错误的可能性)和块大小(15 很大,较小也足够)。
根据你的说法,我的猜测是校准有问题。您应该尝试检查校正后的图像,如果存在问题,请尝试获取新的数据集(或在网上找到更好的数据集)并在那里校准您的图像。一旦你可以正确地校准和校正你的图像,你应该会得到更好的结果。 我看到代码类似于教程 here,所以我想这是正确的,主要问题是图像。希望对你有帮助,如果你测试看看问题出在哪里,我可以帮助你更多!