Python实现双目标定位算法

文章目录

  • 前言
  • 程序与解析:

  • 前言

      在双目视觉中,标定摄像机是一个非常重要的步骤。本文将展示如何用Python和OpenCV对双目相机进行标定。

    程序与解析:

      首先,需要准备标定图片,将分别从左侧和右侧拍摄多张不同角度的标定图片,并把它们存储在两个不同的文件夹中。接下来,需要定义一个棋盘格参数,这里我使用了一个8×11格的黑白棋盘格,每个方块大小为15毫米。

      接着,使用OpenCV读取所有的标定图片,并检测棋盘格角点。使用cornerSubPix函数进行亚像素级别的角点检测,以得到更加准确的角点坐标。如果左右图像的角点都被检测到,则将角点存储到对应的列表中。

      存储完角点之后,使用cv2.calibrateCamera函数计算摄像机的内参数矩阵和畸变系数。需要注意的是,需要分别对左右摄像机进行标定。有了左右摄像机的内参数矩阵和畸变系数之后,接下来就可以进行双目相机的标定了。

      使用cv2.stereoCalibrate函数来标定双目相机。在此函数中,需要传递左右摄像机的内参数矩阵和畸变系数,以及之前存储的角点坐标。函数将返回一些重要的参数供后续使用,比如旋转矩阵、平移矩阵、本质矩阵、基础矩阵等等。

      最后,打印出计算出来的一些重要参数的值,比如左右摄像机的内参数矩阵、畸变系数、旋转矩阵、平移矩阵、本质矩阵和基础矩阵。

    import numpy as np
    import cv2
    import os
    
    # 获取标定图片路径
    path_left = "./data/left/"
    path_right = "./data/right/"
    
    # 定义棋盘格参数
    CHESSBOARD_SIZE = (8, 11)
    CHESSBOARD_SQUARE_SIZE = 15  # mm
    
    # 获取图片列表
    img_list_left = sorted(os.listdir(path_left))
    img_list_right = sorted(os.listdir(path_right))
    
    # 定义物理坐标系下的角点坐标
    objp = np.zeros((CHESSBOARD_SIZE[0] * CHESSBOARD_SIZE[1], 3), np.float32)
    objp[:, :2] = np.mgrid[0:CHESSBOARD_SIZE[0], 0:CHESSBOARD_SIZE[1]].T.reshape(-1, 2) * CHESSBOARD_SQUARE_SIZE
    
    # 定义检测角点的终止准则
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
    
    # 定义用于存储角点坐标的列表
    obj_points = []
    img_points_left = []
    img_points_right = []
    
    # 读取标定图片并检测角点
    for i in range(len(img_list_left)):
        img_l = cv2.imread(path_left + img_list_left[i])
        print(img_list_left[i])
        img_r = cv2.imread(path_right + img_list_right[i])
        gray_l = cv2.cvtColor(img_l, cv2.COLOR_BGR2GRAY)
        gray_r = cv2.cvtColor(img_r, cv2.COLOR_BGR2GRAY)
    
        # 检测角点
        ret_l, corners_l = cv2.findChessboardCorners(gray_l, CHESSBOARD_SIZE, None)
        ret_r, corners_r = cv2.findChessboardCorners(gray_r, CHESSBOARD_SIZE, None)
    
        # 如果左右图像的角点都被检测到,则将角点存储到对应的列表中
        if ret_l and ret_r:
            obj_points.append(objp)
    
            # 通过亚像素级别的角点检测得到更准确的角点坐标
            cv2.cornerSubPix(gray_l, corners_l, (11, 11), (-1, -1), criteria)
            img_points_left.append(corners_l)
            cv2.drawChessboardCorners(img_l, CHESSBOARD_SIZE, corners_l, ret_l)
            cv2.imshow("Chessboard Corners - Left", cv2.resize(img_l,(img_l.shape[1]//2,img_l.shape[0]//2)))
            cv2.waitKey(50)
    
            cv2.cornerSubPix(gray_r, corners_r, (11, 11), (-1, -1), criteria)
            img_points_right.append(corners_r)
            cv2.drawChessboardCorners(img_r, CHESSBOARD_SIZE, corners_r, ret_r)
            cv2.imshow("Chessboard Corners - Right", cv2.resize(img_r,(img_r.shape[1]//2,img_r.shape[0]//2)))
            cv2.waitKey(50)
    
    cv2.destroyAllWindows()
    
    print("Number of chessboard images used for calibration: ", len(obj_points))
    
    # 标定摄像机
    ret_l, mtx_l, dist_l, rvecs_l, tvecs_l = cv2.calibrateCamera(obj_points, img_points_left, gray_l.shape[::-1],None,None)
    ret_r, mtx_r, dist_r, rvecs_r, tvecs_r = cv2.calibrateCamera(obj_points, img_points_right, gray_r.shape[::-1],None,None)
    
    # 标定双目摄像机
    flags = 0
    flags |= cv2.CALIB_FIX_INTRINSIC
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
    ret, M1, d1, M2, d2, R, T, E, F = cv2.stereoCalibrate(
            obj_points, img_points_left, img_points_right,
            mtx_l, dist_l, mtx_r, dist_r,
            gray_l.shape[::-1], criteria=criteria, flags=flags)
    
    print("内参数矩阵M1:\n", M1)
    print("畸变系数d1:\n", d1)
    print("内参数矩阵M2:\n", M2)
    print("畸变系数d2:\n", d2)
    print("旋转矩阵R:\n", R)
    print("平移矩阵T:\n", T)
    print("本质矩阵E:\n", E)
    print("基础矩阵F:\n", F)
    
    
    

    作者:小张Tt

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python实现双目标定位算法

    发表回复