如何使用OpenCV中的stereoCalibrate()函数获得不错的精度

问题描述 投票:0回答:1

我试图通过校准两个相机并使用 StereoCalibrate 函数,使用 OpenCV python 库对 3D 位置进行三角测量。我希望相机能够连接到杆的末端并测量距离相机 5m 左右的位置。大部分代码与 Temuge Batpurev 使用的代码类似(来源:https://temugeb.github.io/opencv/python/2021/02/02/stereo-camera-calibration-and-triangulation.html)当我通过我的代码运行他的校准图像时,返回的 RSME 值(他的代码中的“ret”,我的代码中的 retStereo)是 Temuge 概述的预期 2.4。

当我使用自己的图像时,这些图像是通过 GoPro 10 上的 GPS 进行时间同步的,我的平均图像约为 50。最初,我以为这是因为我校准的区域太大,但近距离观察时,我仍然得到大约 50

目前的校准方法: 从靠近摄像机的地方开始,棋盘不会超出任何一个摄像机的画面,慢慢地挥动棋盘。确保它沿着两个摄像机框架的边缘以及中心运行,然后向后移动并在不同深度重复此操作。

我尝试过的事情:

  1. 增加棋盘方格尺寸(48mm、61mm、109mm)
  2. 增加棋盘上的行/列数
  3. 改变照明条件
  4. 更多校准图像,我使用脚本从视频中提取帧,所以我通常使用 20+ 校准帧
  5. 使用较小的区域进行三角测量
  6. 查看一台相机处于一定角度而不是平行相机是否有变化
  7. 检查 findChessboardCorner 函数实际上找到了棋盘的角点
  8. 确保棋盘位于多个不同位置(底角、顶角、每个摄像机的框架中心)
  9. 在视频中靠近或远离摄像机。
  10. 更改了 criteria 和 criteria_stereo 变量,看看是否有任何改变

我最近视频的图像,109mm 方块:

我的代码:

############### FIND CHESSBOARD CORNERS - OBJECT POINTS AND IMAGE POINTS #############################

chessboardSize = (8,5) # Other chessboard sizes used - (5,3) OR (9,6)

# Paths to the captured frames (should be in synch) (stereoLeft and stereoRight)
CALIBRATION_IMAGES_PATH_LEFT = 'images_vid\\stereoLeft\\*.png'
CALIBRATION_IMAGES_PATH_RIGHT = 'images_vid\\stereoRight\\*.png'

# termination criteria
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

objp = np.zeros((chessboardSize[0] * chessboardSize[1], 3), np.float32) # creates 9*6 list of (0.,0.,0.)
objp[:,:2] = np.mgrid[0:chessboardSize[0],0:chessboardSize[1]].T.reshape(-1,2) # formats list with (column no., row no., 0.) where max column no. = 8, and max row no. = 5

size_of_chessboard_squares_mm = 109
objp = objp * size_of_chessboard_squares_mm

# Arrays to store object points and image points from all the images.
objpoints = [] # 3d point in real world space
imgpointsL = [] # 2d points in image plane.
imgpointsR = [] # 2d points in image plane.

imagesLeft = sorted(glob.glob(CALIBRATION_IMAGES_PATH_LEFT))
imagesRight = sorted(glob.glob(CALIBRATION_IMAGES_PATH_RIGHT))

for imgLeft, imgRight in zip(imagesLeft, imagesRight):
    
    imgL = cv.imread(imgLeft)
    imgR = cv.imread(imgRight)
    grayL = cv.cvtColor(imgL, cv.COLOR_BGR2GRAY)
    grayR = cv.cvtColor(imgR, cv.COLOR_BGR2GRAY)
            
    # Get the corners of the chess board
    retL, cornersL = cv.findChessboardCorners(grayL, chessboardSize, None)
    retR, cornersR = cv.findChessboardCorners(grayR, chessboardSize, None)

    # Add object points and image points if chess board corners are found        
    if retL and retR == True:

        objpoints.append(objp) 

        cornersL = cv.cornerSubPix(grayL, cornersL, (11,11), (-1,-1), criteria)
        imgpointsL.append(cornersL)

        cornersR = cv.cornerSubPix(grayR, cornersR, (11,11), (-1,-1), criteria)
        imgpointsR.append(cornersR)

        #Draw corners for user feedback
        cv.drawChessboardCorners(imgL, chessboardSize, cornersL, retL)
        cv.imshow('img left', imgL)
        cv.drawChessboardCorners(imgR, chessboardSize, cornersR, retR)
        cv.imshow('img right', imgR)
        cv.waitKey()


cv.destroyAllWindows()

############# CALIBRATION #######################################################

retL, cameraMatrixL, distL, rvecsL, tvecsL = cv.calibrateCamera(objpoints, imgpointsL, frameSize, None, None)
heightL, widthL, channelsL = imgL.shape
newCameraMatrixL, roi_L = cv.getOptimalNewCameraMatrix(cameraMatrixL, distL, (widthL, heightL), 1, (widthL, heightL))

retR, cameraMatrixR, distR, rvecsR, tvecsR = cv.calibrateCamera(objpoints, imgpointsR, frameSize, None, None)
heightR, widthR, channelsR = imgR.shape
newCameraMatrixR, roi_R = cv.getOptimalNewCameraMatrix(cameraMatrixR, distR, (widthR, heightR), 1, (widthR, heightR))

######### Stereo Vision Calibration #############################################
## stereoCalibrate Output: retStereo is RSME, newCameraMatrixL and newCameraMatrixR are the intrinsic matrices for both
                ## cameras, distL and distR are the distortion coeffecients for both cameras, rot is the rotation matrix,
                ## trans is the translation matrix, and essentialMatrix and fundamentalMatrix are self descriptive
                
# R and T are taken from stereoCalibrate to use in triangulation
header = ['Rotation','Translation', 'ProjectionLeft', 'ProjectionRight'] # for the csv file

flags = 0
flags = cv.CALIB_FIX_INTRINSIC

criteria_stereo= (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 100, 0.0001)

retStereo, newCameraMatrixL, distL, newCameraMatrixR, distR, rot, trans, essentialMatrix, fundamentalMatrix = cv.stereoCalibrate(objpoints, imgpointsL, imgpointsR, cameraMatrixL, distL, cameraMatrixR, distR, grayL.shape[::-1], criteria_stereo, flags)
print(retStereo)
print('stereo vision done')

我的代码或校准方法是否有任何直接标志?或者改进代码的建议?感谢您花时间帮助我:)

python opencv camera-calibration triangulation
1个回答
0
投票

我用我的图像尝试了你的代码,并得到 RSME=0.6202543526131407。所以你发布的代码似乎工作正常。

首先,我注意到灯或用作校准板的屏幕上可见的任何东西的一些反射。这可能会使 findChessboardCorners 函数感到困惑。 我不太喜欢使用屏幕来渲染校准图案,因为屏幕很闪亮,并且分辨率仅限于屏幕的分辨率。我建议购买下降校准板。好的可以在这里找到https://calib.io/

其次,用校准板靠近相机。距离越近,可见的细节越多,校准效果就越好。

第三,对左右相机的图像进行去畸变并渲染以查看内部参数是否正确。

© www.soinside.com 2019 - 2024. All rights reserved.