【问题标题】:Straightforward solution on how to stereo calibration and rectifications OpenCV?关于如何立体校准和纠正 OpenCV 的直接解决方案?
【发布时间】:2016-07-29 07:51:57
【问题描述】:

我一直在研究这个话题将近一个星期,但还没有找到任何可靠的解决方案。 有趣的是,没有人发布过关于如何使用 OpenCV 校准和校正立体相机以计算深度的简单解决方案,从这里和那里计算深度(this 用于校准,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)

上面的输出是下图

如您所见,图像未纠正!

问题:

  • 代码有什么问题?

【问题讨论】:

  • 在两个输入图像中棋盘是否完全可见?
  • 可能你的棋盘应该只包含完整的正方形,而不是那些在边界处被裁剪的正方形。也许算法将它们误解为扭曲的全正方形并试图不扭曲它们。
  • @Micka 是的,棋盘是完全可见的,它来自OpenCV的标准立体图像集(见leftright图像),张贴的图像是校正过程的输出很奇怪!
  • 边界处的裁剪正方形应该不是问题。这就是我使用calibration.cpp 左侧图像样本得到的结果。应该可以对立体校准样本做同样的事情。
  • image_width: 640 image_height: 480 board_width: 9 board_height: 6 square_size: 1. aspectRatio: 1. flags: 2 camera_matrix: !!opencv-matrix rows: 3 cols: 3 dt: d data: [ 5.3590117051349637e+02, 0., 3.4227429926016583e+02, 0., 5.3590117051349637e+02, 2.3557560607943688e+02, 0., 0., 1. ] distortion_coefficients: !!opencv-matrix rows: 5 cols: 1 dt: d data: [ -2.6643160989580222e-01, -3.8505305722612772e-02, 1.7844280073183410e-03, -2.7702634246810361e-04, 2.3850218962079497e-01 ] avg_reprojection_error: 3.9229331915929899e-01

标签: python opencv image-processing video-processing


【解决方案1】:

我找不到我做错了什么导致错误的答案,但值得我找到一个解决方案,可以纠正 OK 等等!
我遇到了StereoVision 库,考虑到它的文档级别较低,我设法获取/编写了以下快照,这些快照可以校准和纠正。

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()

以下是我在问题中发布的同一图像的更正结果。 虽然为了计算视差图它需要调整它的参数(包提供了一个工具)但它会完成这项工作:)

【讨论】:

  • 你有没有找到更好的解决方案?我有同样的问题@dariush
  • @KaranJoisher 我想是的,但我不记得是什么了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-30
  • 2013-10-12
  • 2017-10-18
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
  • 1970-01-01
相关资源
最近更新 更多