关于如何对 OpenCV 进行立体校准和校正的直接解决方案?
Straightforward solution on how to stereo calibration and rectifications OpenCV?
我已经研究了将近一个星期的这个话题,但还没有找到任何可靠的解决方案。
有趣的是,从来没有人发布过 直接 解决方案,说明如何使用 OpenCV 校准和校正立体相机,以便从这里和那里计算深度(this for calibration and this整改,虽然发布的代码不是很完整)我想出了以下代码快照,但它没有纠正图像 OK!!
import numpy as np
import cv2
import glob
# 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((6*9,3), np.float32)
objp[:,:2] = np.mgrid[0:9,0:6].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.
# calibrate stereo
for side in ['left', 'right']:
counter = 0
images = glob.glob('images/%s*.jpg' %side)
objpoints[side] = [];
imgpoints[side] = [];
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv2.findChessboardCorners(gray, (9,6),None)
# If found, add object points, image points (after refining them)
if ret == True:
objpoints[side].append(objp)
cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
imgpoints[side].append(corners)
counter += 1
assert counter == len(images), "missed chessboard!!"
stereocalib_criteria = (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS, 100, 1e-5)
stereocalib_flags = cv2.CALIB_FIX_ASPECT_RATIO | cv2.CALIB_ZERO_TANGENT_DIST | cv2.CALIB_SAME_FOCAL_LENGTH | cv2.CALIB_RATIONAL_MODEL | cv2.CALIB_FIX_K3 | cv2.CALIB_FIX_K4 | cv2.CALIB_FIX_K5
retval,cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, R, T, E, F = cv2.stereoCalibrate(objpoints['left'], imgpoints['left'], imgpoints['right'], (640, 480), criteria = stereocalib_criteria, flags = stereocalib_flags)
rectify_scale = 0.1 # 0=full crop, 1=no crop
R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, (640, 480), R, T, alpha = rectify_scale)
left_maps = cv2.initUndistortRectifyMap(cameraMatrix1, distCoeffs1, R1, P1, (640, 480), cv2.CV_16SC2)
right_maps = cv2.initUndistortRectifyMap(cameraMatrix2, distCoeffs2, R2, P2, (640, 480), cv2.CV_16SC2)
# Assuming you have left01.jpg and right01.jpg that you want to rectify
lFrame = cv2.imread('images/left01.jpg')
rFrame = cv2.imread('images/right01.jpg')
left_img_remap = cv2.remap(lFrame, left_maps[0], left_maps[1], cv2.INTER_LANCZOS4)
right_img_remap = cv2.remap(rFrame, right_maps[0], right_maps[1], cv2.INTER_LANCZOS4)
for line in range(0, int(right_img_remap.shape[0] / 20)):
left_img_remap[line * 20, :] = (0, 0, 255)
right_img_remap[line * 20, :] = (0, 0, 255)
cv2.imshow('winname', np.hstack([left_img_remap, right_img_remap]))
cv2.waitKey(0)
exit(0)
上面的输出是下图
如您所见,图像未校正!!
问题:
- 代码有什么问题?
我找不到我做错了什么导致了不正确的答案,但对于它的价值,我找到了一个解决方案,它确实纠正了 OK 和更多!
我遇到了 StereoVision 库并考虑到它的文档级别较低,我设法 fetch/write 以下快照可以校准和纠正 OK。
import cv2
import os.path
import numpy as np
from stereovision.calibration import StereoCalibrator, StereoCalibration
from stereovision.blockmatchers import StereoBM, StereoSGBM
calib_dir = 'data/config/calibration'
if(not os.path.exists(calib_dir)):
calibrator = StereoCalibrator(9, 6, 2, (480, 640))
for idx in range(1, 14):
calibrator.add_corners((cv2.imread('images/left%02d.jpg' %idx), cv2.imread('images/right%02d.jpg' %idx)))
calibration = calibrator.calibrate_cameras()
print "Calibation error:", calibrator.check_calibration(calibration)
calibration.export(calib_dir)
calibration = StereoCalibration(input_folder=calib_dir)
if True:
block_matcher = StereoBM()
else:
block_matcher = StereoSGBM()
for idx in range(1, 14):
image_pair = (cv2.imread('images/left%02d.jpg' %idx), cv2.imread('images/right%02d.jpg' %idx))
rectified_pair = calibration.rectify(image_pair)
disparity = block_matcher.get_disparity(rectified_pair)
norm_coeff = 255 / disparity.max()
cv2.imshow('Disparity %02d' %idx, disparity * norm_coeff / 255)
for line in range(0, int(rectified_pair[0].shape[0] / 20)):
rectified_pair[0][line * 20, :] = (0, 0, 255)
rectified_pair[1][line * 20, :] = (0, 0, 255)
cv2.imshow('Rect %02d' %idx, np.hstack(rectified_pair))
cv2.waitKey()
以下是我在问题中发布的同一张图片的纠正结果。
虽然计算视差图需要调整其参数(软件包提供了一个工具)但它会完成这项工作:)
我已经研究了将近一个星期的这个话题,但还没有找到任何可靠的解决方案。 有趣的是,从来没有人发布过 直接 解决方案,说明如何使用 OpenCV 校准和校正立体相机,以便从这里和那里计算深度(this for calibration and this整改,虽然发布的代码不是很完整)我想出了以下代码快照,但它没有纠正图像 OK!!
import numpy as np
import cv2
import glob
# 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((6*9,3), np.float32)
objp[:,:2] = np.mgrid[0:9,0:6].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.
# calibrate stereo
for side in ['left', 'right']:
counter = 0
images = glob.glob('images/%s*.jpg' %side)
objpoints[side] = [];
imgpoints[side] = [];
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret, corners = cv2.findChessboardCorners(gray, (9,6),None)
# If found, add object points, image points (after refining them)
if ret == True:
objpoints[side].append(objp)
cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
imgpoints[side].append(corners)
counter += 1
assert counter == len(images), "missed chessboard!!"
stereocalib_criteria = (cv2.TERM_CRITERIA_MAX_ITER + cv2.TERM_CRITERIA_EPS, 100, 1e-5)
stereocalib_flags = cv2.CALIB_FIX_ASPECT_RATIO | cv2.CALIB_ZERO_TANGENT_DIST | cv2.CALIB_SAME_FOCAL_LENGTH | cv2.CALIB_RATIONAL_MODEL | cv2.CALIB_FIX_K3 | cv2.CALIB_FIX_K4 | cv2.CALIB_FIX_K5
retval,cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, R, T, E, F = cv2.stereoCalibrate(objpoints['left'], imgpoints['left'], imgpoints['right'], (640, 480), criteria = stereocalib_criteria, flags = stereocalib_flags)
rectify_scale = 0.1 # 0=full crop, 1=no crop
R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, (640, 480), R, T, alpha = rectify_scale)
left_maps = cv2.initUndistortRectifyMap(cameraMatrix1, distCoeffs1, R1, P1, (640, 480), cv2.CV_16SC2)
right_maps = cv2.initUndistortRectifyMap(cameraMatrix2, distCoeffs2, R2, P2, (640, 480), cv2.CV_16SC2)
# Assuming you have left01.jpg and right01.jpg that you want to rectify
lFrame = cv2.imread('images/left01.jpg')
rFrame = cv2.imread('images/right01.jpg')
left_img_remap = cv2.remap(lFrame, left_maps[0], left_maps[1], cv2.INTER_LANCZOS4)
right_img_remap = cv2.remap(rFrame, right_maps[0], right_maps[1], cv2.INTER_LANCZOS4)
for line in range(0, int(right_img_remap.shape[0] / 20)):
left_img_remap[line * 20, :] = (0, 0, 255)
right_img_remap[line * 20, :] = (0, 0, 255)
cv2.imshow('winname', np.hstack([left_img_remap, right_img_remap]))
cv2.waitKey(0)
exit(0)
上面的输出是下图
如您所见,图像未校正!!
问题:
- 代码有什么问题?
我找不到我做错了什么导致了不正确的答案,但对于它的价值,我找到了一个解决方案,它确实纠正了 OK 和更多!
我遇到了 StereoVision 库并考虑到它的文档级别较低,我设法 fetch/write 以下快照可以校准和纠正 OK。
import cv2
import os.path
import numpy as np
from stereovision.calibration import StereoCalibrator, StereoCalibration
from stereovision.blockmatchers import StereoBM, StereoSGBM
calib_dir = 'data/config/calibration'
if(not os.path.exists(calib_dir)):
calibrator = StereoCalibrator(9, 6, 2, (480, 640))
for idx in range(1, 14):
calibrator.add_corners((cv2.imread('images/left%02d.jpg' %idx), cv2.imread('images/right%02d.jpg' %idx)))
calibration = calibrator.calibrate_cameras()
print "Calibation error:", calibrator.check_calibration(calibration)
calibration.export(calib_dir)
calibration = StereoCalibration(input_folder=calib_dir)
if True:
block_matcher = StereoBM()
else:
block_matcher = StereoSGBM()
for idx in range(1, 14):
image_pair = (cv2.imread('images/left%02d.jpg' %idx), cv2.imread('images/right%02d.jpg' %idx))
rectified_pair = calibration.rectify(image_pair)
disparity = block_matcher.get_disparity(rectified_pair)
norm_coeff = 255 / disparity.max()
cv2.imshow('Disparity %02d' %idx, disparity * norm_coeff / 255)
for line in range(0, int(rectified_pair[0].shape[0] / 20)):
rectified_pair[0][line * 20, :] = (0, 0, 255)
rectified_pair[1][line * 20, :] = (0, 0, 255)
cv2.imshow('Rect %02d' %idx, np.hstack(rectified_pair))
cv2.waitKey()
以下是我在问题中发布的同一张图片的纠正结果。