相机的内参标定(实现原理+具体操作流程+实验结果)

文章介绍了相机内参标定的重要性,主要是为了校正镜头畸变。内容涵盖相机成像原理、相机畸变类型(径向、离心、薄棱镜),并详细解析了张正友博士的标定法,包括具体的数学模型和操作流程。此外,还提供了使用ROS的cameracalibration工具进行标定的步骤,以及标定结果的分析。
摘要由CSDN通过智能技术生成

这篇主要是总结梳理一下关于学习到的相机内参标定的知识。计划分为原理介绍,具体操作流程,标定实验结果三个模块。

首先先简单解释下为什么要进行相机标定这个操作,我们知道生活中实际使用的相机镜头都是透镜,初中时的物理就讲过,只有通过光心的光线才是沿直线传播的,而大部分的光线在通过透镜后会发生折射,从而在一定程度上改变传播的角度。越靠近透镜的边缘,改变的角度也就越大,这会造成相机所成的像产生距离上的拉伸以及形状的改变。这个现象称为相机畸变。(相机的畸变分为多种,后边会具体介绍)。而标定操作其实就是通过一系列的计算校准后得到修正参数,通过这些参数修正后就可以得到与我们人眼看到的景象相同的图像,也就是,将三维景象转换成去除畸变后的二维图像。

一、相机的成像原理

这张图就是世界中的点到相机图像上的点的转换关系图。转换过程涉及四个坐标系。红色的是相机坐标系,原点就是相机光心所在的位置。黄色的是世界中的三维点。绿色的是图像坐标系,从世界点到图像点坐标的转换实际上是运用了相似三角形的计算。

最后再将得到的点坐标x,y平移到黑色的像素坐标系,如此就完成了世界坐标点向像素坐标系点的转换,也就是我们所说的三维点向二维平面的投影。

通过数学公式和框图来表达转换关系:

我们将公式中的R称为旋转矩阵,t称为平移矩阵或平移向量。R|t合起来称作外参矩阵。将

称为相机的内参矩阵,也就是我们今天主要讨论的话题。

我们现在知道,从数学原理上我们有着一套准确的公式来完成三维世界点到二维像素点的转换。而完成这一系列转换的思想是简单的相似三角形。我们也在前面提到过,通过相机标定来求解内参参数的目的——是为了去除相机成像的畸变。此时回看上边的公式,就会发现上述的转换和计算是没有考虑畸变的,此时如果不去除畸变直接成像就会是这种效果:

 可以看到,本来笔直的大楼看起来弯曲了,而且越是相片的四周,看起来弯曲程度越大。这就是镜头畸变导致的。我们可以通过标定操作去除畸变使得照片中的楼看起来是笔直的。

实际上,相机的畸变是非线性的,不能再简单地通过相似三角形来计算并修正,曾经的相机标定需要用到精密的参照物与复杂的操作,直到一位我们国人大佬,张正友博士提出了一套著名的使用棋盘格的标定法——张氏标定法。下面我们就介绍相机畸变的具体种类以及张氏标定法是如何修正这些畸变的。

二、相机的畸变与张氏标定法

相机的畸变,通常分为三大类。径向畸变、离心畸变以及薄棱镜畸变。

(1)径向畸变

使像点产生径向位置的偏差称为径向畸变。这也是相机中最常见的一种畸变——因为光线通过透镜一定会产生折射。径向畸变又可以具体分为正向(枕形)畸变【左图】和负向(桶形)畸变【右图】。

我们可以通过下面的公式对x,y进行修正,这也是切向畸变的表达形式

 (2)离心畸变

 相机的光学中心与几何中心不一致(镜头各器件的光学中心)所造成的畸变称为离心畸变。广义上讲,离心畸变既包含径向畸变,又包含镜头主光轴不对称所造成的切向畸变(不过我们通常将径向畸变单独分成一类)。同样的,对切向畸变的修正可以通过以下公式描述:

(3)薄棱镜畸变

镜头设计缺陷与加工安装误差所造成的畸变称为薄棱镜畸变,这种畸变会同时引起径向畸变和切向畸变(想象一下相机的镜头安装的不正,或者镜头不够平整)。高价位的镜头可以忽略薄棱镜畸变。薄棱镜畸变可以通过下式进行描述:

张氏标定法只关注径向畸变,通过五个左右的畸变系数进行修正,通常为k1,k2,p1,p2,k3(五个畸变系数的情况下)。k的个数通过计算的结果与修正的效果进行调整,可多可少,实际计算过程中,如果考虑太多高阶的畸变参数,会导致标定求解的不稳定。我做的实验中通常是4~5个畸变系数。

(4)张氏标定法

接下来我们具体介绍一下张氏标定法的思路。

由前边提到的坐标转换公式,使用K来代替内参矩阵,可以写成:

再将内外参矩阵合并为H,可以写成:

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

 因为R旋转矩阵为正交矩阵,存在:

代入H可得求出两组A和H的公式:

矩阵A包含5个元素,需要3组H才能解出A的唯一封闭解,因此在标定时需拍摄3组以上的图片。由A可计算出相应的外参矩阵。此时的求解过程忽略相机畸变的影响。对内外参应用最小二乘方法估计实际存在的径向畸变的畸变系数(忽略切向畸变),最后通过极大似然法进行优化,得到精度较高的解。这就是张氏标定法的大致思路。现在很多标定工具使用的方法和思路都是张氏标定法或以此为基础进行改进的。

ps:学习时查了不少资料,发现大多是将畸变和理论情况下的投影分开介绍。对去畸变究竟发生在什么时候讲的都是模棱两可,只是知道在标定过程中通过非线性优化完成去畸变操作。我个人认为,相机的去畸变是发生在将三维世界点坐标转换到图像坐标系的时候(三维世界点转换到相机坐标系,再归一化到图像坐标系后,此时能够发现本该是直线的地方弯曲了或缩放比例不正确,这时通过调整畸变系数对坐标进行修正,使得大部分坐标在修正后能够较为准确)【当然要看到最终成像时的畸变才能去针对性地进行去畸变操作,所以这段话貌似又没什么价值,可能是这个原因所以很多大佬的科普贴中才没有专门进行说明吧】

三、具体实现流程

接下来我们介绍相机的内参标定究竟是如何操作的。张氏标定法使用的是带有棋盘格的标定板,这一方法目前已经有现成的工具可以实现,我尝试过的方法有ROS的camera calibration以及matlab的相机内参标定工具箱。这里介绍一下ROS的camera calibration工具。

Ubuntu18.04安装ROS melodic_qq_41361687的博客-CSDN博客

matlab相机内参标定_qq_41361687的博客-CSDN博客

安装好ROS后(我使用的是ROS-Melodic),需要安装标定工具包

sudo apt-get install ros-melodic-camera-calibration

随后需要找到我们的相机驱动文件,启动launch文件(我用的是普通usb相机,驱动可以在网上搜索usb_cam找到)

roscore

roslaunch usb_cam usb_cam.launch

这样相机就启动了,接下来启动标定工具

rosrun camera_calibration cameracalibrator.py --size 11x9 --square 0.095 image:=/camera/image_raw camera:=/camera --no-service-check

这里size是指所使用棋盘格的尺寸,数字指的是角点的数量(可以先简单理解成不同颜色的边界交汇点),比如下图,我用的是12个格子长,10个格子宽的棋盘格,那么角点数量就是11 × 9;square指的是棋盘格格子的边长,单位是m;之后的两个是接收的topic,ROS通过topic来发布并接受信息。实际标定中,所使用的topic可以在运行相机驱动后通过输入

rostopic list

进行查看。然后找到其中image与camera发布的话题。将参数都设置好之后就可以回车启动,正式开始标定了。

使用的棋盘格标定板如图所示,从图上可以看出,相机确实存在畸变,视场中的标定板和棋盘格都出现了不同程度的形变。

运行标定程序后,界面上左侧是当前的镜头画面,右侧会有一个工具栏,标有X,Y,Size,Screw这四个指标,以及calibrate,save,load三个功能键。其中X对应左右方向(x轴),Y对应上下方向(y轴),Size对应远近(z轴),Screw对应俯仰(以自身中心为轴的偏转)。

在上图右侧terminal中可以看到,标定程序会自动提取能够检测出角点时的图片帧。我们需要做的是,移动标定板的位姿,包括上下左右,远近,以及俯仰(总结来说,就是在能够检测出角点的情况下,使标定板尽可能出现在相机视场中的每个位置)使得标定界面中的四个指标X,Y,Size,Screw下边的线尽可能拉满。这代表着标定程序已经在该指标下采集到了足够多质量好的数据。

当四个指标都差不多拉满的时候,我们可以点击calibrate,此时程序会停止数据采集并开始计算内参参数与畸变系数。点击save可以将得到的计算结果进行保存。

四、标定结果

标定结果会以yaml文件格式保存,包括内参3*3矩阵、外参3*4矩阵、以及畸变系数(由于我们只进行了内参参数intrinsic matrix的计算,可以看到外参参数extrinsic matrix虽然也在标定结果里但只是一个单位矩阵)。

想得到去畸变后的画面,可以使用image_proc包来对摄像头图像进行去畸变。image_proc会从指定的topic上提取相机校正参数,这个topic默认为/xxx_camera/camera_info。这里xxx_camera是名字空间,可以指定。

ROS_NAMESPACE=usb_cam rosrun image_proc image_proc

确保指定名字空间中有image_raw和camera_info的主题。image_proc会将处理后的图像发布到/xxx_camera/image_rect和image_rect_color。image_rect是灰度图像,image_rect_color是彩色图像。

接下来需要把校正得到的yaml文件内容发布到/xxx_camera/camera_info上去。 需要我们在启动usb_cam时为其指定camera_info_url参数,通过修改usb_cam.launch文件完成,在其中添加如下:

<param name="camera_info_url" type="string" value="file://$(find usb_cam)/ost.yaml" />

#<param name="camera_info_url" type="string" value="file:///home/xxx/ost.yaml" />

这样在usb_cam启动时就会加载该相机参数文件。通过指定的topic(如image_rect和/image_rect_color),我们就可以得到去畸变后的图像。

(PS:相机畸变不可能完全去除,因为我们使用的方法是通过非线性优化近似,通常画面的四个角会留有一定程度的畸变【肉眼可见】,而靠近中心位置的畸变则去除的效果较好【几乎观察不到畸变】,越好的相机在出厂时的去畸变会越精细,但不代表畸变完全被去除了,只是人眼不易观察到)。

以上就是通过ROS的camera calibration实现相机内参标定的大致操作。

另外:

以下是我在学习标定以及在梳理这篇博客时参考的内容,在此感谢各位大佬的资料,大家可以一并查阅。

相机标定(Camera calibration)原理、步骤_AI人工智能科学的博客-CSDN博客

最详细、最完整的相机标定讲解_卍卐没想到的博客-CSDN博客

[图像]摄像机标定(2) 张正友标定推导详解_祥知道的博客-CSDN博客

相机内参标定是通过对相机进行一系列的参数估计,以便能够准确地将图像坐标转换为真实世界中的物体坐标。在Python中,可以使用OpenCV库来进行相机内参标定。 以下是一个基本的相机内参标定的Python代码示例: ```python import numpy as np import cv2 # 定义棋盘格尺寸 pattern_size = (8, 6) # 准备用于保存棋盘角点的列表 obj_points = [] # 保存物体点的3D坐标 img_points = [] # 保存图像点的2D坐标 # 生成物体点的坐标 objp = np.zeros((np.prod(pattern_size), 3), np.float32) objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2) # 读取图像 images = [...] # 填入需要标定的图像路径列表 for img_path in images: img = cv2.imread(img_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 查找棋盘角点 ret, corners = cv2.findChessboardCorners(gray, pattern_size, None) if ret: obj_points.append(objp) img_points.append(corners) # 在图像上绘制角点并显示 cv2.drawChessboardCorners(img, pattern_size, corners, ret) cv2.imshow('Chessboard Corners', img) cv2.waitKey(500) # 显示图片500毫秒 cv2.destroyAllWindows() # 进行相机内参标定 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, gray.shape[::-1], None, None) # 打印相机内参矩阵和畸变系数 print("相机内参矩阵:") print(mtx) print("\n畸变系数:") print(dist) ``` 上述代码中,首先定义了棋盘格的尺寸,然后准备用于保存棋盘角点的列表。接下来,生成物体点的3D坐标,并读取需要标定的图像。使用`cv2.findChessboardCorners()`函数查找图像中的棋盘角点,并将找到的角点保存到`img_points`列表中。然后在图像上绘制角点并显示。 最后,使用`cv2.calibrateCamera()`函数进行相机内参标定,返回相机内参矩阵和畸变系数。打印出这些参数即可完成相机内参标定。 请注意,上述代码仅提供了一个基本的相机内参标定示例,实际应用中可能需要更多的处理和参数调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值