如何使用openCV中的立体元素()函数获得体面的精度

发布于 2025-01-31 00:43:03 字数 5022 浏览 3 评论 0 原文

我试图通过校准两个摄像机并使用立体校准函数来使用OpenCV Python库进行三角测量。我希望摄像机能够连接到杆的末端,并测量距离摄像头约5m的位置。大多数代码类似于batpurev使用的代码(来源:

当我使用自己的图像(通过GOPRO 10s的GPS)进行时间同步时,我平均大约50个。最初,我认为这是因为我在一个区域中进行了校准,但要闭上我的当前

校准方法 大约为50个: 从摄像头附近开始,没有棋盘从框架上驶出任何一个相机,慢慢地挥舞着木板。确保它沿着摄像机和中心的框架边缘运行,然后再向后移动并在各个深度重复它。

我尝试过的事情:

  1. 增加棋盘方尺寸(48mm,61mm,109mm),
  2. 增加了棋盘上棋盘上的行/柱数量
  3. 更换照明条件
  4. ,我使用脚本从视频中提取框架,所以我通常使用20 校准框架
  5. +使用较小区域进行
  6. 以三角剖分查看是否有一个零置的摄像头,而不是让摄像头平行
  7. 检查FindchessboardCorner功能实际上找到了棋盘的角落,
  8. 以确保棋盘在许多不同的位置(底角) ,顶角,每个相机的框架中心)
  9. 在视频中向相机移动和远离相机。
  10. 更改了标准和标准_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')

有任何即时标志,我的代码或我的校准方法是否有什么?还是改进代码的建议?感谢您抽出宝贵的时间帮助我:)

I'm attempting to be able to triangulate a 3D position using the OpenCV python library by calibrating two cameras and using the stereoCalibrate function. I want the cameras to be able to be attached to the ends of a bar and measure positions around 5m away from the cameras. The majority of code is similar to the code used by Temuge Batpurev (Source: https://temugeb.github.io/opencv/python/2021/02/02/stereo-camera-calibration-and-triangulation.html) and when I run his calibration images through my code, the RSME value ("ret" in his code, retStereo in my code) returned is the 2.4 expected as Temuge outlined.

When I use my own images, which are time-synched through GPS on GoPro 10s, I average around 50. Originally, I thought it was because I was calibrating for too large of an area but close up I still get around 50

Current Calibration Method:
Starting close to the cameras, without the chessboard going out of frame for either camera, slowly waving the board around. Ensuring it runs along the edges of the frames for both cameras as well as the center before moving backwards and repeating this at various depths.

Things I have tried:

  1. Increasing the size of chessboard squares (48mm, 61mm, 109mm)
  2. Increasing the number of rows/columns on the chessboard
  3. Changing lighting conditions
  4. More calibration images, I use a script to extract frames from a video so I normally use 20+ calibration frames
  5. Using a smaller area to triangulate
  6. Seeing if there was a change having one camera at an angle as opposed to having the cameras parallel
  7. Checking the findChessboardCorner function actually finds the corners of the chessboard
  8. Ensuring the chessboard is in many different positions (bottom corner, top corner, center of the frames for each camera)
  9. Moving towards and away from the camera in videos.
  10. Changed the criteria and criteria_stereo variables to see if that changed anything

Images of my most recent video, 109mm squares: LHSImage RHSImage

My code:

############### 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')

Are there any immediate flags with my code or my calibration method? Or recommendations for improving the code? Thanks for taking your time to help me :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

甜尕妞 2025-02-07 00:43:03

我尝试了您的图像代码,并获得了RSME = 0.6202543526131407。因此,您发布的代码似乎正常。

首先,我注意到灯或您用作校准板的屏幕上可见的任何反射。这可能会使FindchessboardCorners功能感到困惑。
我不是使用屏幕来渲染校准模式的忠实拥护者,因为屏幕是有光泽的,并且分辨率仅限于屏幕的分辨率。我建议购买下降校准板。可以在此处找到好的, https://calib.io/

其次,使用校准板更靠近相机。越接近,越多的细节就可以看到,校准越好。

第三,将图像从左和右相机中删除,然后渲染它们以查看固有参数是否正确。

I tried your code with my images and get an RSME=0.6202543526131407. So you posted code seems to work fine.

First, I notice some reflections from a lamp or whatever visible on the screen which you are using as calibration board. That might confuse the findChessboardCorners function.
I am not a big fan of using screens for rendering the calibration pattern, since screens are shiny and the resolution is restricted to the resolution of the screen. I suggest buying descent calibration boards. Good ones can be found here https://calib.io/.

Second, move closer to the cameras with your calibration board. The closer, the more details are visible and the better the calibration becomes.

Third, undistort an image from the left and right camera and render them to see if the intrinsic parameters are correct.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文