Python单目/双目相机标定(使用opencv自带图片)

前言:基于Python版本的相机校正,并且校正结果与官方对比主要差值较小。话不多说,直接上代码。

1.导入库

包括opencv, numpy和文件操作库os

import cv2
import numpy as np
import os

2.编写函数

本次主要有两个比较麻烦的要解决,其一,批量读取,第二,真实坐标的写入。我使用os编写的读取文件函数,比较垃圾,大佬请用glob或者其他的。真实坐标主要是标定板上内点的真实相片坐标,通过参考其他大佬总结的出

def getImageList(img_dir):
    # 获取图片文件夹位置,方便opencv读取
    # 参数:照片文件路径
    # 返回值:数组,每一个元素表示一张照片的绝对路径
    imgPath = []
    if os.path.exists(img_dir) is False:
        print('error dir')
    else:
        for parent, dirNames, fileNames in os.walk(img_dir):
            for fileName in fileNames:
                imgPath.append(os.path.join(parent, fileName))
    return imgPath
def getObjectPoints(m, n, k):
    # 计算真实坐标
    # 参数:内点行数,内点列, 标定板大小
    # 返回值:数组,(m*n行,3列),真实内点坐标
    objP = np.zeros(shape=(m * n, 3), dtype=np.float32)
    for i in range(m * n):
        objP[i][0] = i % m
        objP[i][1] = int(i / m)
    return objP * k

3.主程序

# 相机标定参数设定(单目,双目)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
criteria_stereo = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 计算标定板真实坐标,标定板内点9*6,大小10mm*10mm
objPoint = getObjectPoints(9, 6, 10)

objPoints = []
imgPointsL = []
imgPointsR = []
# 相片路径,自行修改
imgPathL = 'D:/SA/2021.3/6.1/l/'
imgPathR = 'D:/SA/2021.3/6.1/r/'
filePathL = getImageList(imgPathL)
filePathR = getImageList(imgPathR)

for i in range(len(filePathL)):
    # 分别读取每张图片并转化为灰度图
    imgL = cv2.imread(filePathL[i])
    imgR = cv2.imread(filePathR[i])
    grayL = cv2.cvtColor(imgL, cv2.COLOR_BGR2GRAY)
    grayR = cv2.cvtColor(imgR, cv2.COLOR_BGR2GRAY)
    # opencv寻找角点
    retL, cornersL = cv2.findChessboardCorners(grayL, (9, 6), None)
    retR, cornersR = cv2.findChessboardCorners(grayR, (9, 6), None)
    if (retL & retR) is True:
        # opencv对真实坐标格式要求,vector<vector<Point3f>>类型
        objPoints.append(objPoint)
        # 角点细化
        cornersL2 = cv2.cornerSubPix(grayL, cornersL, (5, 5), (-1, -1), criteria)
        cornersR2 = cv2.cornerSubPix(grayR, cornersR, (5, 5), (-1, -1), criteria)
        imgPointsL.append(cornersL2)
        imgPointsR.append(cornersR2)
# 对左右相机分别进行单目相机标定(复制时格式可能有点问题,用pycharm自动格式化)
retL, cameraMatrixL, distMatrixL, RL, TL = cv2.calibrateCamera(objPoints, imgPointsL, (640, 480), None, None)
retR, cameraMatrixR, distMatrixR, RR, TR = cv2.calibrateCamera(objPoints, imgPointsR, (640, 480), None, None)
# 双目相机校正
retS, mLS, dLS, mRS, dRS, R, T, E, F = cv2.stereoCalibrate(objPoints, imgPointsL, 
imgPointsR, cameraMatrixL,
                                                           distMatrixL, cameraMatrixR, 
                                                           distMatrixR, (640, 480),
                                                           criteria_stereo, flags=cv2.CALIB_USE_INTRINSIC_GUESS)
# 标定结束,结果输出,cameraMatrixL,cameraMatrixR分别为左右相机内参数矩阵
# R, T为相机2与相机1旋转平移矩阵
print(cameraMatrixL)
print('*' * 20)
print(cameraMatrixR)
print('*' * 20)
print(R)
print('*' * 20)
print(T)

4.其他一些问题

1.关于真实坐标。这个是以标定板为平面z=0的内点真实坐标,单独输出就是这样的。是标定板由左上内点开始,然后是右侧点,接着下面的点:(是这个顺序)。

其次,仔细看opencv图片可以发现内点9*6和6*9是一样的,你可以自己试试,我试过了,一样的

a = getObjectPoints(9, 6, 10)
print(a)
[[ 0.  0.  0.]
 [10.  0.  0.]
 [20.  0.  0.]
 [30.  0.  0.]
 [40.  0.  0.]
 [50.  0.  0.]
 [60.  0.  0.]
 [70.  0.  0.]
 [80.  0.  0.]
 [ 0. 10.  0.]
 [10. 10.  0.]
 [20. 10.  0.]
 [30. 10.  0.]
 [40. 10.  0.]
 [50. 10.  0.]
 [60. 10.  0.]
 [70. 10.  0.]
 [80. 10.  0.]
 [ 0. 20.  0.]
 [10. 20.  0.]
 [20. 20.  0.]
 [30. 20.  0.]
 [40. 20.  0.]
 [50. 20.  0.]
 [60. 20.  0.]
 [70. 20.  0.]
 [80. 20.  0.]
 [ 0. 30.  0.]
 [10. 30.  0.]
 [20. 30.  0.]
 [30. 30.  0.]
 [40. 30.  0.]
 [50. 30.  0.]
 [60. 30.  0.]
 [70. 30.  0.]
 [80. 30.  0.]
 [ 0. 40.  0.]
 [10. 40.  0.]
 [20. 40.  0.]
 [30. 40.  0.]
 [40. 40.  0.]
 [50. 40.  0.]
 [60. 40.  0.]
 [70. 40.  0.]
 [80. 40.  0.]
 [ 0. 50.  0.]
 [10. 50.  0.]
 [20. 50.  0.]
 [30. 50.  0.]
 [40. 50.  0.]
 [50. 50.  0.]
 [60. 50.  0.]
 [70. 50.  0.]
 [80. 50.  0.]]

2.opencv+Python和matlab和opencv+C++的结果都不一样,但是主要部分都是大致相同的(比如说焦距都是533, 旋转矩阵对角线值差不多,平移矩阵大致为-33左右)。这就造成了计算三维坐标的不统一。emm,再想想解决办法吧

猜你喜欢

转载自blog.csdn.net/qq_36076137/article/details/118383472