相机标定原理

相机标定意义

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

在后面可以看到 世界坐标系与 像素坐标系的 转换 关系 里面的 几个矩阵,就是要通过标定求得的 相关 参数

相机标定原理

所以 相机标定的 目的 就是 求 相关 参数

相机标定参数

具体参数如下:

  • 1、相机内参 是一个 4*3的矩阵
  • 2、相机外参 相机坐标系与世界坐标系的 旋转和平移
  • 3、畸变参数 5 个 参数

相关坐标系

   相关的坐标系有 
  • 世界坐标系
  • 相机坐标系
  • 像素坐标系

在这里插入图片描述

世界坐标系

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

相机坐标系

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

像素坐标系、图像坐标系

在这里插入图片描述
像素坐标系是一个二维直角坐标系,反映了相机CCD/CMOS芯片中像素的排列情况。原点位于图像的左上角,轴、轴分别于像面的两边平行。像素坐标系中坐标轴的单位是像素(整数)。

像素坐标系不利于坐标变换,因此需要建立图像坐标系,其坐标轴的单位通常为毫米(mm),原点是相机光轴与相面的交点(称为主点),即图像的中心点,轴、轴分别与轴、轴平行。故两个坐标系实际是平移关系,即可以通过平移就可得到。

相机坐标系转换为世界坐标系

转换方程为:
在这里插入图片描述
其中R为3_3的旋转矩阵,t为3_1的平移矢量

这个就是外参

像素坐标系转换为图像坐标系

在这里插入图片描述
其中,dx、dy分别为像素在x、y轴方向上的一个像素物理尺寸,为主点(图像原点)坐标。

相机坐标系转换为图像坐标系

在这里插入图片描述

世界坐标系转换为像素坐标系

在这里插入图片描述

其中 f 为摄像机的焦距,单位一般是mm;dx,dy 为像元尺寸;u0,v0 为图像中心。fx = f/dx, fy = f/dy,分别称为x轴和y轴上的归一化焦距.

其中相机的内参和外参可以通过张正友标定获取。通过最终的转换关系来看,一个三维中的坐标点,的确可以在图像中找到一个对应的像素点,但是反过来,通过图像中的一个点找到它在三维中对应的点就很成了一个问题,因为我们并不知道等式左边的Zc的值。

环境信息

操作系统:ubuntu 20.04
ROS版本:noetic
功能包:camera_calibration
相机:Flir 工业相机

通过camera_calibration 功能包进行标定

这个功能包在装ROS的时候一般就装好了,不需要手动去安装。可以看这个目录下面,有没有下面的文件

/opt/ros/noetic/lib/camera_calibration

在这里插入图片描述
如果有则不需要安装了

准备一个标定板

图

例如我的如上面的图

其中内部角点的数量是 横着9个角点 竖着6个角点 参数是 —size 9x6
棋盘方格的尺寸为 15mm 参数是 —square 0.015

接入待标定的相机

启动相机驱动

roslaunch spinnaker_sdk_camera_driver acquisition.launch

通过 rostopic list查看当前消息名称

/acquisition_node/parameter_descriptions
/acquisition_node/parameter_updates
/camera
/camera_array/cam0/camera_info
/camera_array/cam0/image_raw
/camera_array/cam0/image_raw/compressed
/camera_array/cam0/image_raw/compressed/parameter_descriptions
/camera_array/cam0/image_raw/compressed/parameter_updates
/camera_array/cam0/image_raw/compressedDepth
/camera_array/cam0/image_raw/compressedDepth/parameter_descriptions
/camera_array/cam0/image_raw/compressedDepth/parameter_updates
/camera_array/cam0/image_raw/theora
/camera_array/cam0/image_raw/theora/parameter_descriptions
/camera_array/cam0/image_raw/theora/parameter_updates
/rosout
/rosout_agg
/vision_nodelet_manager/bond

其中/camera_array/cam0/image_raw就是图像的消息

再通过rviz 确认下

rviz

在这里插入图片描述
图像没问题则开始标定

开始标定
camera_calibration功能包的运行有些参数需要提前知道,在上面也作了总结
wiki的介绍和 代码 最上面 参数 的介绍 一样,有一些必须要有的参数 设置

1、–size 棋盘的尺寸 注意 这个是 内部 角点的 个数 不是 格子数量 如上面我们建立的棋盘 横着 是5个黑5个白,所以是9个角点,所以竖着是 6个角点 顾 参数 设置应为 --size 9x6 也不要写成–size 7*6 识别不了
2、–p 较准目标 的 模式 默认是 棋盘,所以我们的就可以不设置了
3、–q 棋盘方格的尺寸 单位为m 顾 我们的应该为 --square 0.015
4、image:=/camera_array/cam0/image_raw 指定 图像的 topic
5、camera:=/cam0 指定 相机 的 名称

所以运行功能包的指令为:

rosrun camera_calibration cameracalibrator.py --size 9x6 --square 0.015 image:=/camera_array/cam0/image_raw camera:=/camera

会报错

rosrun camera_calibration cameracalibrator.py --size 9x6 --square 0.015 image:=/camera_array/cam0/image_raw camera:=/camera
Waiting for service /camera/set_camera_info ...
Service not found

通过将上面的指令换成如下:

rosrun camera_calibration cameracalibrator.py --size 9x6 --square 0.015 image:=/camera_array/cam0/image_raw camera:=/camera --no-service-check

即可成功启动功能包

小幅度晃动棋盘,即可添加样本
在这里插入图片描述
终端中也会出现加的样本

*** Added sample 1, p_x = 0.786, p_y = 0.324, p_size = 0.320, skew = 0.162
*** Added sample 2, p_x = 0.709, p_y = 0.367, p_size = 0.340, skew = 0.081
*** Added sample 3, p_x = 0.686, p_y = 0.500, p_size = 0.366, skew = 0.057
*** Added sample 4, p_x = 0.715, p_y = 0.641, p_size = 0.391, skew = 0.069
*** Added sample 5, p_x = 0.730, p_y = 0.377, p_size = 0.396, skew = 0.195
*** Added sample 6, p_x = 0.752, p_y = 0.291, p_size = 0.396, skew = 0.287
*** Added sample 7, p_x = 0.730, p_y = 0.544, p_size = 0.401, skew = 0.161
*** Added sample 8, p_x = 0.711, p_y = 0.528, p_size = 0.406, skew = 0.367
*** Added sample 9, p_x = 0.694, p_y = 0.544, p_size = 0.395, skew = 0.524
*** Added sample 10, p_x = 0.810, p_y = 0.241, p_size = 0.429, skew = 0.353
*** Added sample 11, p_x = 0.845, p_y = 0.199, p_size = 0.440, skew = 0.505
*** Added sample 12, p_x = 0.683, p_y = 0.312, p_size = 0.444, skew = 0.359
*** Added sample 13, p_x = 0.741, p_y = 0.332, p_size = 0.474, skew = 0.459
*** Added sample 14, p_x = 0.753, p_y = 0.150, p_size = 0.507, skew = 0.512
*** Added sample 15, p_x = 0.881, p_y = 0.136, p_size = 0.571, skew = 0.489
*** Added sample 16, p_x = 0.883, p_y = 0.323, p_size = 0.563, skew = 0.504
*** Added sample 17, p_x = 0.811, p_y = 0.129, p_size = 0.533, skew = 0.402
*** Added sample 18, p_x = 0.739, p_y = 0.203, p_size = 0.492, skew = 0.323

在这里插入图片描述
样本足够丰富后, CALIBRATE的圆圈会变色
点击校正按钮后,会把校正的信息在终端打印出来

mono pinhole calibration...
D = [-0.10645980776596488, 0.10371164929092522, -1.882145769316208e-05, 0.0039944001322395305, 0.0]
K = [1213.3435830577907, 0.0, 744.1505199517793, 0.0, 1217.2369818676787, 586.1543625065199, 0.0, 0.0, 1.0]
R = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
P = [1181.1759033203125, 0.0, 749.6899524539549, 0.0, 0.0, 1194.7589111328125, 586.7730000707706, 0.0, 0.0, 0.0, 1.0, 0.0]
None
# oST version 5.0 parameters
[image]
width
1440
height
1080
[narrow_stereo]
camera matrix
1213.343583 0.000000 744.150520
0.000000 1217.236982 586.154363
0.000000 0.000000 1.000000

distortion
-0.106460 0.103712 -0.000019 0.003994 0.000000
rectification
1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000

projection
1181.175903 0.000000 749.689952 0.000000
0.000000 1194.758911 586.773000 0.000000
0.000000 0.000000 1.000000 0.000000

点击校正按钮后,会把校正的信息在终端打印出来

点击保存后,终端输出

('Wrote calibration data to', '/tmp/calibrationdata.tar.gz')

在tmp的文件夹下会生成一个压缩包,保存的相机的校准信息

解压后,可看到采集的样本信息
在这里插入图片描述
两个文件,内容就是终端输出的内容

更改相机驱动文件的 相机参数

矫正之后的效果
在这里插入图片描述