Python计算机视觉编程--相机标定

文章介绍了相机标定的重要性,目的是校正镜头畸变并重构三维场景。张正友标定法被提及,它简化了传统标定过程,但结果受输入图像质量影响。实验展示了使用OpenCV进行标定的过程,尽管手机相机畸变小,标定效果可能不明显。
摘要由CSDN通过智能技术生成

1.为什么要相机标定?

 在图像测量过程以及机器视觉应用中,为确定空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系,必须建立相机成像的几何模型,这些几何模型参数就是相机参数。

【1】进行摄像机标定的目的:求出相机的内、外参数,以及畸变参数。
【2】标定相机后通常是想做两件事:一个是由于每个镜头的畸变程度各不相同,通过相机标定可以校正这种镜头畸变矫正畸变,生成矫正后的图像;另一个是根据获得的图像重构三维场景。

2.什么叫相机标定?

        在大多数条件下这些参数必须通过实验与计算才能得到,这个求解参数的过程就称之为相机标定(或摄像机标定)

3.为什么相机标定很重要?

      无论是在图像测量或者机器视觉应用中,相机参数的标定都是非常关键的环节,其标定结果的精度及算法的稳定性直接影响相机工作产生结果的准确性。因此,做好相机标定是做好后续工作的前提,提高标定精度是科研工作的重点所在。

4.相机标定方法有哪些?    

相机标定方法有:传统相机标定法、主动视觉相机标定方法、相机自标定法。

传统相机标定法需要使用尺寸已知的标定物,通过建立标定物上坐标已知的点与其图像点之间的对应,利用一定的算法获得相机模型的内外参数。根据标定物的不同可分为三维标定物和平面型标定物。三维标定物可由单幅图像进行标定,标定精度较高,但高精密三维标定物的加工和维护较困难。平面型标定物比三维标定物制作简单,精度易保证,但标定时必须采用两幅或两幅以上的图像。传统相机标定法在标定过程中始终需要标定物,且标定物的制作精度会影响标定结果。同时有些场合不适合放置标定物也限制了传统相机标定法的应用。

        目前出现的自标定算法中主要是利用相机运动的约束。相机的运动约束条件太强,因此使得其在实际中并不实用。利用场景约束主要是利用场景中的一些平行或者正交的信息。其中空间平行线在相机图像平面上的交点被称为消失点,它是射影几何中一个非常重要的特征,所以很多学者研究了基于消失点的相机自标定方法。自标定方法灵活性强,可对相机进行在线定标。但由于它是基于绝对二次曲线或曲面的方法,其算法鲁棒性差。

       基于主动视觉的相机标定法是指已知相机的某些运动信息对相机进行标定。该方法不需要标定物,但需要控制相机做某些特殊运动,利用这种运动的特殊性可以计算出相机内部参数。基于主动视觉的相机标定法的优点是算法简单,往往能够获得线性解,故鲁棒性较高,缺点是系统的成本高、实验设备昂贵、实验条件要求高,而且不适合于运动参数未知或无法控制的场合。

标定工具需要有极高的精度,包括不同平面的角度、特征点的物理距离等,因此制作标定工具十分困难。在2000年华人科学家张正友发现了一种不需要高精度标定板就可以标定出相机参数的很有效的方式。下面对张正友标定法的原理做一些介绍。

整体流程:

一些形式化描述:

2D图像点:m=[u,v]^{^{T}}

3D空间点:M=[X,Y,Z]^{T}

齐次坐标:\tilde{m}=[u,v,1]^{T},\tilde{M}=[X,Y,Z,1]^{T}

描述空间坐标到图像坐标的映射:

s\tilde{m}=K[R|r]\tilde{M},M=\begin{pmatrix} \alpha &\gamma &u_{0} \\ o&\beta &v_{0} \\ 0&0 &1 \end{pmatrix}

其中s表示世界坐标系到图像坐标系的尺度因子,K 表示相机内参数矩阵,(u_{o},v_{0})表示主点坐标,α 和 β 表示焦距与像素横纵比的融合,\gamma表示径向畸变参数。

下面通过实验来实现张正友标定法对照相机进行标定。我准备的是下图这种格子数为12×9,内角点为11×8的棋盘格图片,手机型号为iPhone14pro。

代码:

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((8 * 11, 3), np.float32)
objp[:, :2] = np.mgrid[0:8, 0:11].T.reshape(-1, 2)  # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y

obj_points = []  # 存储3D点
img_points = []  # 存储2D点

images = glob.glob(r"C:\Users\psen2\Desktop\biaoding\*.jpg")
i=0;
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    size = gray.shape[::-1]
    ret, corners = cv2.findChessboardCorners(gray, (8, 11), None)
    #print(corners)

    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, 11), corners, ret)  # 记住,OpenCV的绘制函数一般无返回值
        i+=1;
        cv2.imwrite('conimg'+str(i)+'.jpg', img)
        cv2.waitKey(1500)

print(len(img_points))
cv2.destroyAllWindows()

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)

print("内参数矩阵:\n", mtx) # 内参数矩阵
print("畸变系数:\n", dist)  # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print("旋转向量:\n", rvecs)  # 旋转向量  # 外参数
print("平移向量:\n", tvecs ) # 平移向量  # 外参数

print("-----------------------------------------------------")

img = cv2.imread(images[2])
h, w = img.shape[:2]
# 获取新的相机矩阵和ROI
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
# 进行畸变校正
dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
# 裁剪校正后的图片,去掉黑边
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
# 保存校正后的图片
cv2.imwrite('undistorted.jpg', dst)
print("校正后的图片已保存到文件 'undistorted.jpg'")

 

 畸变矫正前的图像:

 

 畸变矫正后的图像:

分析:
    从实验结果中可以看到成功计算出了照相机内部参数和外部参数。但是畸变矫正的结果很不理想。这是因为现在手机相机已经做的很好了,拍摄的图片基本没有畸变。而由于棋盘格的精度不足以及拍摄的照片的因素导致畸变矩阵偏离实际,使得畸变矫正反而产生了不好的结果。
    同时在实验过程中也体会到了张正友标定法的优点和一些问题:首先张正友标定法克服了传统标定法需要的高精度标定物、算法复杂的缺点,而仅需使用一个打印出来的棋盘格就可以。而且使用方便,标定简单,相机和标定板可以任意放置,只需要计算出几个参数就可以得到标定数据。
    但是该方法标定结果的好坏和输入标定图像相关,会导致多次标定结果不一致。同时如果相机镜头存在非径向和切向的非线性畸变,该方法并不能进行处理。大畸变镜头需要手动进行内参初始化,因为这时用H矩阵求初值不准。
 

 

 

 


 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值