zoukankan      html  css  js  c++  java
  • OpenCVPython系列之相机校准实践

    上个教程已经谈到,为了校准摄像头,我们至少需要10种测试模式。现在我们使用示例图片:

    image.png

    用同一相机从不同的位置,不同的角度,拍摄标定板的多张照片(10-20张最佳),将照片放到文件夹中:

    image.png

    设想一张棋盘的图像,需要用于校准摄像头最重要的输入数据是3D真实世界点的集合以及图像中这些点的相应2D坐标。2D图像点我们得能够轻易从图像中找出来。(这些图像点是棋盘中两个黑色方块相互接触的位置)

    那现实世界空间的3D点怎么来呢?这些图像是从一个静止的摄像头上取下来的,并且棋盘被放置成了不同的位置和方向。所以我们得知道(X,Y,Z)值。但是为了简单,我们可以说棋盘在XY平面保持静止(所以 Z总是等于0),并且摄像头也相应的移动了。这样的考虑方式帮助我们可以只算出XY值。现在对于X,Y值,我们可以简单的传入点,比如(0,0), (1,0), (2,0), ... 用于表示点的位置。在这种情况下,我们得到的结果将是棋盘方格的放缩后的大小。但如果我们知道方格尺寸(比方说 30 mm),我们可以传入这样的值(0,0), (30,0), (60,0), ... . 于是我们得到的结果就是mm为单位的。(当前情况下,我们不知道方格的尺寸,因为我们没有取那些图像,所以我们按照方格尺寸放缩的模式传参)。

    3D 点被称为是object points 对象点,而2D 图像上的点被称为 image points 图象点。

    实现步骤:

    1、为了找到棋盘格模板,可使用OpenCV中的函数cv2.findChessboardCorners()。需要告诉程序标明模板是何规格,在这里我们使用的是13x11的棋盘格,含有12x10的内部角点。这个函数如果检测到模板,会返回对应的角点,并返回true。当然不一定所有的图像都能找到需要的模板,所以我们可以使用多幅图像进行定标。

    2、找到角点后,我们可以使用cv2.cornerSubPix()可以得到更为准确的角点像素坐标。我们也可以使用cv2.drawChessboardCorners()将角点绘制到图像上显示。

    3、通过前面的步骤,得到了用于标定的三维点和与其对应的图像上的二维点对。我们使用cv2.calibrateCamera()进行标定,这个函数会返回标定结果、相机的内参数矩阵、畸变系数、旋转矩阵和平移向量。

    4、通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。

    5、使用cv2.undistort()方法去除畸变

    相关函数的参数解释在这里不再详细说明。

    来看代码:

     
    import cv2
    import numpy as np
    import glob
     
    # 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
    criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)
     
    # 获取标定板角点的位置
    objp = np.zeros((6 * 4, 3), np.float32)
    objp[:, :2] = np.mgrid[0:6, 0:4].T.reshape(-1, 2)  # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y
     
    obj_points = []  # 存储3D点
    img_points = []  # 存储2D点
     
    images = glob.glob("D:/Python/ComputerView/test1/*.jpg")
    for fname in images:
        img = cv2.imread(fname)
        cv2.imshow('img',img)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
     
        size = gray.shape[::-1]
        ret, corners = cv2.findChessboardCorners(gray, (6, 4), None)
        print(ret)
     
        if ret:
     
            obj_points.append(objp)
     
            corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)  # 在原角点的基础上寻找亚像素角点
            #print(corners2)
            if [corners2]:
                img_points.append(corners2)
            else:
                img_points.append(corners)
     
            cv2.drawChessboardCorners(img, (8, 6), corners, ret)  # 记住,OpenCV的绘制函数一般无返回值
            cv2.imshow('img', img)
            cv2.waitKey(10)
     
    print(len(img_points))
    cv2.destroyAllWindows()
     
    # 标定
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)
     
    print("ret:", ret)
    print("mtx:\n", mtx) # 内参数矩阵
    print("dist:\n", dist)  # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
    print("rvecs:\n", rvecs)  # 旋转向量  # 外参数
    print("tvecs:\n", tvecs ) # 平移向量  # 外参数
     
    print("-----------------------------------------------------")
    img = cv2.imread(images[2])
    h, w = img.shape[:2]
    newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))#显示更大范围的图片(正常重映射之后会删掉一部分图像)
    print (newcameramtx)
    dst = cv2.undistort(img,mtx,dist,None,newcameramtx)
    x,y,w,h = roi
    dst1 = dst[y:y+h,x:x+w]
    cv2.imwrite('D:/Python/ComputerView/test1/calibresult3.jpg', dst1)
    print ("dst的大小为:", dst1.shape)
    image.png
    天道酬勤 循序渐进 技压群雄
  • 相关阅读:
    Mix and Build(简单DP)
    Is It A Tree?(并查集)
    Paths on a Grid(简单组合数学)
    Code(组合数学)
    Round Numbers(组合数学)
    Inviting Friends(二分+背包)
    Communication System(dp)
    Human Gene Functions
    Pearls
    敌兵布阵(线段树HDU 1166)
  • 原文地址:https://www.cnblogs.com/wuyuan2011woaini/p/15660124.html
Copyright © 2011-2022 走看看