【计算机视觉】:(4)相机模型与参数标定

1. 针孔相机模型

1.1. 简介

四个坐标系概念

世界坐标系(world coordinate)(xw,yw,zw),也称为测量坐标系,是一个三维直角坐标系,以其为基准可以描述相机和待测物体的空间位置。世界坐标系的位置可以根据实际情况自由确定。世界坐标系的最小单位为mm。

相机坐标系(camera coordinate)(xc,yc,zc),也是一个三维直角坐标系,原点位于镜头光心处,xc、yc轴分别与像面的两边平行,zc轴为镜头光轴,与像平面垂直。相机坐标系的最小单位为mm。

图像坐标系(image coordinate)(x,y),是像平面上的二维直角坐标系。图像坐标系的原点为镜头光轴与像平面的交点(也称主点,principal point),它的x轴与相机坐标系的xc轴平行,它的y轴与相机坐标系的yc轴平行。图像坐标系的最小单位为mm

像素坐标系(pixel coordinate)(u,v),是图像处理工作中常用的二维直角坐标系,反映了相机CCD/CMOS芯片中像素的排列情况。它的原点位于图像左上角,横坐标u表示像素所在的列,纵坐标v表示像素所在的行。像素坐标系与图像坐标系可以简单理解为平移关系,它们同处于像平面。像素坐标系的x轴与图像坐标系的u轴平行,像素坐标系的y轴与图像坐标系的v轴平行。像素坐标系的最小单位为像素

一般来说,标定的过程分为两个部分:

  1. 世界坐标系转换为相机坐标系,这一步是三维点到三维点的转换,包括**[R|t]相机外参矩阵**)等参数;
  2. 相机坐标系转为图像坐标系,这一步是三维点到二维点的转换,包括 K (相机内参矩阵)等参数;

在这里插入图片描述

1.2. 相机坐标系转为图像坐标系

在这里插入图片描述
在这里插入图片描述

C点表示相机的中心点,也是相机坐标系的中心点;
Z轴表示相机的主轴;
p点所在的平面表示相机的像平面,也就是图片坐标系所在的二维平面;
p点表示像主点,主轴与像平面相交的点
C点到p点的距离,也就是图中的f表示相机的焦距;
像平面上的x和y坐标轴与相机坐标系上的X和Y坐标轴互相平行;
相机坐标系是以X、Y 、Z三个轴组成的且原点在C点,度量值为米(m);
像平面坐标系是以x、y两个轴组成且原点在p点,度量值为米(m);
图像坐标系一般指图片相对坐标系,在这里可以认为和像平面坐标系在一个平面上,不过原点是在图片的角上,而且度量值为像素的个数(pixel)。

在这里插入图片描述

相机坐标系到图像坐标系的转换:
在这里插入图片描述
引入齐次坐标简单来说就是为了统一,方便计算,可自行去了解齐次坐标的作用。

像主点偏移
由于各种原因,生产原因,个人使用原因等等,相机光心要想都处在原点可能性较小,会发生一定的偏移。如下图, u 0 u_0 u0 v 0 v_0 v0分别是x、y方向上的偏移量。相机标定就是确定相机的内部参数和外部参数。这里K表示内参矩阵,接下来我们还要知道外参矩阵。
{ u = f X Z + u 0 v = f Y Z + v 0 \left\{\begin{matrix} u=\frac{fX}{Z}+u_0\\ v=\frac{fY}{Z}+v_0 \end{matrix}\right. {u=ZfX+u0v=ZfY+v0
在这里插入图片描述
畸变现象
由于透镜制造精度以及组装工艺的偏差会引入畸变,导致原始图像的失真。镜头的畸变分为径向畸变和切向畸变两类:
1.图像径向畸变:沿着透镜半径方向分布的畸变,产生原因是光线在原理透镜中心的地方比靠近中心的地方更加弯曲,这种畸变在普通廉价的镜头中表现更加明显,径向畸变主要包括桶形畸变和枕形畸变两种。
在这里插入图片描述
在这里插入图片描述

2.图像**切向畸变:**由于透镜本身与相机传感器平面(成像平面)或图像平面不平行而产生的,这种情况多是由于透镜被粘贴到镜头模组上的安装偏差导致。

所以对于镜头畸变一共有5个参数k1, k2, k3,p1,p2需要校准,opencv输出的即便参数顺序是k1, k2,p1, p2,k3因为k3没那么重要。

1.4. 内参矩阵

因此K中还需要加入畸变参数,进行畸变矫正
在这里插入图片描述

1.5. 外参矩阵

一般情况下,世界坐标系和相机坐标系不重合,这时,世界坐标系中的某一点P PP要投影到像面上时,先要将该点的坐标转换到相机坐标系下。刚体从世界坐标系转换到相机坐标系的过程,可以通过旋转和平移来得到。因此相机的外部参数就包括了旋转、平移矩阵。
在这里插入图片描述
其中 [ R ∣ t ] [R|t] [Rt]为外参矩阵

2. 相机参数标定

标定方法

2.1. 传统相机标定

最简单的相机标定为线性标定,即不考虑相机的畸变而只考虑空间坐标转换。
每个坐标点有X,Y两个变量,可列两个方程,相机内参有5个未知数(α,β,s, u 0 , v 0 u_0,v_0 u0,v0),外参平移和旋转各3个(三个轴的旋转参数3个,3个平移参数,共六个),共有11个变量,因此至少需要6个特征点来求解。

2.2. 非线性标定

当镜头畸变明显时必须考虑畸变,一般较为便宜的网络摄像头畸变特别大,而价格较贵的工业摄像头则畸变很小,因为其中已经嵌入了许多消除畸变的程序。这时线性模型转化为非线性模型,需要通过非线性标定方法求解。有最速下降法,遗传算法,高斯牛顿法和神经网络算法等。

2.3. 张正友相机标定法

在这里插入图片描述
在这里插入图片描述

注:张正友标定只考虑了径向畸变,没有考虑切向畸变

在这里插入图片描述

H为3x3矩阵,并且有一个元素作为齐次坐标,则有8个未知元素,一组坐标对应两个方程,则至少需要四组对应的点即可算出单应性矩阵H。

张正友相机标定流程:

  1. 打印一张棋盘格A4纸张(黑白间距已知),并贴在一个平板上
  2. 针对棋盘格拍摄若干张图片(不同方向,调整棋盘格或者相机)(一般10-20张)
  3. 在图片中检测特征点(Harris角点)
  4. 根据角点位置信息及图像中的坐标,求解 Homographic矩阵(单应性矩阵)
  5. 利用解析解估算方法计算出5个内部参数,以及 6个外部参数
  6. 根据极大似然估计策略,设计优化目标并实现参数的refinement
    在这里插入图片描述

优点
• 只需一个平面
• 标定过程中无需知道棋盘格的方位
• 大量开源代码!

2.1. 实验数据

共拍摄14张图片
在这里插入图片描述

2.2. 代码实现

import cv2
import numpy as np
import glob

np.set_printoptions(suppress=True)

# 找棋盘格角点
# 阈值
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 棋盘格模板规格
w = 6  # 内角点个数,内角点是和其他格子连着的点
h = 4

# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐标,记为二维矩阵
objp = np.zeros((w * h, 3), np.float32)
objp[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2)
# 储存棋盘格角点的世界坐标和图像坐标对
objpoints = []  # 在世界坐标系中的三维点
imgpoints = []  # 在图像平面的二维点

images = glob.glob('*.jpg')
i = 0
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 找到棋盘格角点
    # 棋盘图像(8位灰度或彩色图像)  棋盘尺寸  存放角点的位置
    ret, corners = cv2.findChessboardCorners(gray, (w, h), None)
    # 如果找到足够点对,将其存储起来
    if ret == True:
        # 角点精确检测
        # 输入图像 角点初始坐标 搜索窗口为2*winsize+1 死区 求角点的迭代终止条件
        i += 1
        cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        objpoints.append(objp)
        imgpoints.append(corners)
        # 将角点在图像上显示
        cv2.drawChessboardCorners(img, (w, h), corners, ret)
        cv2.imshow('findCorners', img)
        cv2.imwrite('h' + str(i) + '.jpg', img)
        cv2.waitKey(10)
cv2.destroyAllWindows()
# 标定、去畸变
# 输入:世界坐标系里的位置 像素坐标 图像的像素尺寸大小 3*3矩阵,相机内参数矩阵 畸变矩阵
# 输出:标定结果 相机的内参数矩阵 畸变系数 旋转矩阵 平移向量
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
# mtx:内参数矩阵
# dist:畸变系数
# rvecs:旋转向量 (外参数)
# tvecs :平移向量 (外参数)
print(("ret:"), ret)
print(("内参矩阵:\n"), mtx)  # 内参数矩阵
print(("畸变参数:\n"), dist)  # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print(("旋转向量(外参数):\n"), rvecs)  # 旋转向量  # 外参数
print(("平移向量(外参数):\n"), tvecs)  # 平移向量  # 外参数
# 去畸变
img2 = cv2.imread('1.jpg')
h, w = img2.shape[:2]
# 我们已经得到了相机内参和畸变系数,在将图像去畸变之前,
# 我们还可以使用cv.getOptimalNewCameraMatrix()优化内参数和畸变系数,
# 通过设定自由自由比例因子alpha。当alpha设为0的时候,
# 将会返回一个剪裁过的将去畸变后不想要的像素去掉的内参数和畸变系数;
# 当alpha设为1的时候,将会返回一个包含额外黑色像素点的内参数和畸变系数,并返回一个ROI用于将其剪裁掉
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 0, (w, h))  # 自由比例参数

dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)
# 根据前面ROI区域裁剪图片
# x, y, w, h = roi
# dst = dst[y:y + h, x:x + w]
cv2.imwrite('calibresult.jpg', dst)

# 反投影误差
# 通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。
# 通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,
# 然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。
total_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
    total_error += error
print(("total error: "), total_error / len(objpoints))

2.3. 结果及分析

(1)角点检测结果
使用findChessboardCorners函数提取角点,这里的角点专指的是标定板上的内角点,保存了每一张棋盘格的角点检测结果,每一张均可检测到角点。随便拿了一个结果展示。
在这里插入图片描述

(2)内参矩阵
在这里插入图片描述
(3)外参矩阵
在这里插入图片描述
在这里插入图片描述

(4)分析
1.标定图片最好多点,不然可能导致不准确。
2.平移拍摄参数变化较小,棋盘若是倾斜,参数变化较大。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值