为什么要标定?
相机标定的目的是为了确定相机内部参数和外部参数,以便修正图像并将图像坐标映射到世界坐标,或者从世界坐标映射到图像坐标。这个过程是计算机视觉和三维感知任务的关键步骤之一,它有以下主要目的:
-
减小畸变:相机镜头和传感器可能引入径向和切向畸变,使得图像中的直线变得弯曲或者物体的形状不准确。通过标定相机,可以矫正这些畸变,使图像更准确。
-
确定内部参数(intrinsic parameters):内部参数包括焦距、主点坐标和相机畸变参数。这些参数是描述相机如何捕捉世界的重要因素,它们的准确值对于计算深度、距离和姿态等任务至关重要,相机内参标定就是为了获取精确的内部参数。
distortion_model: "plumb_bob"
D: [0.0, 0.0, 0.0, 0.0, 0.0]
K: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 910.145263671875, 347.9687194824219, 0.0, 0.0, 1.0]
P: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 0.0, 910.145263671875, 347.9687194824219, 0.0, 0.0, 0.0, 1.0, 0.0]
- 确定外部参数:外部参数包括相机的位置和方向。这些参数描述了相机相对于世界坐标系的位置和朝向,允许将图像坐标映射到世界坐标,这对于机械臂的抓取很有帮助。
该篇不涉及外参标定,将在机械臂手眼标定的文章中讲解相机的外参标定。
<!-- xyz="-0.162861 0.177661 -0.626113" rpy="1.45853 -2.03383 1.49474" -->
<node pkg="tf2_ros" type="static_transform_publisher" name="camera_link_broadcaster"
args="-0.162861 0.177661 -0.626113 -0.173987 -0.703383 -0.14907 0.672873 Link6 left_arm_camera_link" />
- 相机姿态估计:相机标定还可用于估计相机在拍摄图像时的姿态,即相机的旋转和平移。这对于虚拟现实、增强现实、机器人导航和定位等应用至关重要。
标定的原理[选看]
使用OpenCV标定
通过OpenCV进行相机标定的原理可以参考OpenCV相机校准和三维重建文档。
ros-noetic-camera-calibration
此处使用ros-noetic-camera-calibration工具包来方便地在ROS1 Noetic中标定相机。
camera_calibration
包是一个允许使用棋盘格来轻松校准单目或立体相机的ROS包。
相机信息中的内参相关内容
以Intel Realsense彩色相机为例,以下是彩色相机的信息。
# rostopic echo /right_arm_camera/color/camera_info
---
header:
seq: 32308
stamp:
secs: 1694683940
nsecs: 530882359
frame_id: "right_arm_camera_color_optical_frame"
height: 720
width: 1280
distortion_model: "plumb_bob"
D: [0.0, 0.0, 0.0, 0.0, 0.0]
K: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 910.145263671875, 347.9687194824219, 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: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 0.0, 910.145263671875, 347.9687194824219, 0.0, 0.0, 0.0, 1.0, 0.0]
binning_x: 0
binning_y: 0
roi:
x_offset: 0
y_offset: 0
height: 0
width: 0
do_rectify: False
---
header:
seq: 32309
stamp:
secs: 1694683940
nsecs: 564413071
frame_id: "right_arm_camera_color_optical_frame"
height: 720
width: 1280
distortion_model: "plumb_bob"
D: [0.0, 0.0, 0.0, 0.0, 0.0]
K: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 910.145263671875, 347.9687194824219, 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: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 0.0, 910.145263671875, 347.9687194824219, 0.0, 0.0, 0.0, 1.0, 0.0]
binning_x: 0
binning_y: 0
roi:
x_offset: 0
y_offset: 0
height: 0
width: 0
do_rectify: False
---
其中包括相机的内部参数有关的参数:
当处理相机内参时,常见的三个参数是 D
、K
和 P
,此外相关的还有畸变模型。
D
畸变系数(distortion_coefficients):D
是一个通常包含五个元素的数组[k1, k2, p1, p2, k3]
,它用于描述相机图像中的径向和切向畸变。k1
和k2
是径向畸变系数,它们用于描述镜头的弯曲形状,通常是负数。p1
和p2
是切向畸变系数,它们用于描述镜头的畸变不对称性,通常是很小的值。k3
是一个更高阶的径向畸变系数,通常情况下很小,有时甚至可以忽略。D
用来表示径向和切向畸变。
D: [0.0, 0.0, 0.0, 0.0, 0.0]
K
相机内参矩阵(camera_matrix):K
是一个3x3的矩阵,它包括了相机的内部参数,用于将相机坐标系中的三维点映射到图像平面上的二维坐标。K
的主要元素包括:K[0]
和K[4]
是焦距在图像 x 和 y 轴上的分量,通常以像素为单位。K[2]
和K[5]
是光心在图像 x 和 y 轴上的坐标,也以像素为单位。K[8]
通常是1,是一个归一化参数。
K
包含了焦距和主点的信息。
K: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 910.145263671875, 347.9687194824219, 0.0, 0.0, 1.0]
P
投影矩阵(projection_matrix):P
是一个3x4
的矩阵,它包含了相机的投影参数,用于将相机坐标系中的三维点映射到图像坐标系。P
的元素包括了内参和外参信息。- 其中
P[0]
和P[5]
分别对应于焦距fx
和fy
,用于将相机坐标系的 x 和 y 坐标映射到图像坐标系上。 P[2]
和P[6]
对应于光心的 x 和 y 坐标cx
和cy
。P[3]
和P[7]
通常为0,用于表示没有视角的旋转或平移。P[10]
通常是1,是一个归一化参数。- 投影矩阵
P
包含了相机的内部参数和畸变参数。
P: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 0.0, 910.145263671875, 347.9687194824219, 0.0, 0.0, 0.0, 1.0, 0.0]
distortion_model"
(畸变模型):
distortion_model
是相机标定信息中的一个字段,用于描述相机的畸变模型。
畸变模型是用来描述相机镜头产生的畸变效应的数学模型。
在计算机视觉中,畸变通常分为径向畸变和切向畸变两种主要类型,而畸变模型用于对这些畸变进行建模和校正。
Plumb Bob (钉形畸变模型):
- “plumb_bob” 畸变模型是最常见的畸变模型之一,也是默认的畸变模型。它通常用于描述径向畸变(Radial Distortion)和切向畸变(Tangential Distortion)。
- 径向畸变主要是由于镜头形状不完全圆形引起的,导致图像中心附近的像素与图像边缘的像素之间存在畸变。这种畸变通常用多项式函数建模。
- 切向畸变则是由于相机镜头不完全平行于图像平面引起的,导致图像中心附近的像素存在畸变。切向畸变通常也用多项式函数建模。
- “plumb_bob” 畸变模型使用径向和切向畸变系数(
D
)来描述这两种畸变。
标定的材料
- 棋盘格:需要准备一个大小适中的黑白棋盘格,计算大小
8x6
方格大小9X7的棋盘格是常见的选择,但请注意,内部角点的数量比较少的情况下,标定可能会不够精确。
此处选用了计算大小11x8
,方格大小12x9
的铝基板黑白棋盘格,边长为15mm
作为示例,这些制作好的标定板有更高的标定精度。
方格大小和计算大小是为了方便理解造的名词,将在之后解释。
如果手上没有标定板,也可以在线制作棋盘格并用A4纸打印出来,
推荐的参数如下:
Name | Value |
---|---|
Target Type | Checkerboard |
Board Width | 297 |
Board Height | 210 |
Rows(方格大小) | 7 |
Columns(方格大小) | 9 |
Checker Width [mm] | 25 |
注意事项:需要明确的是,棋盘格的计算大小是指内部角点的数量,按照OpenCV文档的描述,例如 计算大小 8x6
棋盘格实际上包含 9x7
个物理方格,也就是方格大小为9X7
。
如图所示,数内部角点(图上红圈处)只有八个,也就是计算行大小为8
,实际上的行方格数为9
。
在将棋盘格打印出来后,需要贴在平整的表面上。
-
良好的光照条件:确保拍摄相机标定图像的区域光线充足,并且没有遮挡物或其他棋盘格图案。
-
相机:需要标定的相机,已接入ROS1 Noetic,并且使用了
rostopic
获取相机发布的图像话题。
相机需要满足的需求:
- image_pipeline的硬件需求
- camera_driver的硬件需求
同时,相机硬件需要提供适用于ROS的节点,以便能够发布必要的图像话题。
开始标定
单目RGB相机(monocular)
此处以right_arm_camera
为例:
- 1.下载
ros-noetic-camera-calibration
sudo apt install ros-noetic-camera-calibration -y
- 2.修改参数为需要校准的相机的参数
需要获取的参数如下:
参数 | 参考值 | 解释 |
---|---|---|
–size | 8x6 | 棋盘格计算大小8行x6列 |
–square | 0.025 | 棋盘格方格的边长大小0.025米(25mm) |
image:= | /right_arm_camera/color/image_raw | 名为right_arm_camera的相机的彩色相机图像话题 |
camera:= | /right_arm_camera | 名为right_arm_camera相机 |
参数解释请参考camera_calibration文档。
- 3.运行校准程序
rosrun camera_calibration cameracalibrator.py --size 8x6 --square 0.025 image:=/right_arm_camera/color/image_raw camera:=/right_arm_camera
注意:因为校准工具会查找相机节点的set_camera_info
服务,如果无法正确启动,添加以下参数到命令中
--no-service-check
下图为正常打开标定软件的图片:
- 3.调整标定板
按照以下顺序调整标定板,使得相机拍摄尽量多的不同视角下的有效照片:
- 前后移动标定板
- 上下移动标定板
- 左右移动标定板
- 沿Yaw轴旋转标定板
- 沿Pitch轴旋转标定板
- 沿Roll轴旋转标定板
当X、Y、Size、Skew结果都为绿色,非常良好时,点击CALIBRATE
进行标定计算。
标定计算结束后点击SAVE
保存标定结果。
保存的结果将被自动保存在/tmp
目录下,名为calibrationdata.tar.gz
('Wrote calibration data to', '/tmp/calibrationdata.tar.gz')
通过以下命令将其解压到$HOME
目录
# Create dir
mkdir ~/camera_calibration_result/
# Unzip
tar -xzvf /tmp/calibrationdata.tar.gz -C ~/camera_calibration_result/
# Go home
cd ~
标定结果
查看解压到$HOME
目录下的标定结果ost.txt
或者ost.yaml
:
# ost.txt
# oST version 5.0 parameters
[image]
width
1280
height
720
[narrow_stereo]
camera matrix
911.053619 0.000000 651.739848
0.000000 906.641596 351.747917
0.000000 0.000000 1.000000
distortion
0.102865 -0.173613 0.001142 0.005375 0.000000
rectification
1.000000 0.000000 0.000000
0.000000 1.000000 0.000000
0.000000 0.000000 1.000000
projection
918.415080 0.000000 660.158706 0.000000
0.000000 923.612822 352.392856 0.000000
0.000000 0.000000 1.000000 0.000000
# ost.yaml
image_width: 1280
image_height: 720
camera_name: narrow_stereo
camera_matrix:
rows: 3
cols: 3
data: [911.05362, 0. , 651.73985,
0. , 906.6416 , 351.74792,
0. , 0. , 1. ]
distortion_model: plumb_bob
distortion_coefficients:
rows: 1
cols: 5
data: [0.102865, -0.173613, 0.001142, 0.005375, 0.000000]
rectification_matrix:
rows: 3
cols: 3
data: [1., 0., 0.,
0., 1., 0.,
0., 0., 1.]
projection_matrix:
rows: 3
cols: 4
data: [918.41508, 0. , 660.15871, 0. ,
0. , 923.61282, 352.39286, 0. ,
0. , 0. , 1. , 0. ]
和Intel 原厂标定的结果作对比,可以发现参数差不多:
D: [0.0, 0.0, 0.0, 0.0, 0.0]
K: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 910.145263671875, 347.9687194824219, 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: [911.4010620117188, 0.0, 645.8338623046875, 0.0, 0.0, 910.145263671875, 347.9687194824219, 0.0, 0.0, 0.0, 1.0, 0.0]
后续
对于普通未经标定的相机,此时就可以用相机的手段进行内参数据的更新
对于Intel Realsense相机,参考MartyG所述,Realsense相机在出厂前已经标注过,因此通常不再需要再次标注内参。
因此,本文只是拿Realsense相机作为例子,这篇文章仍适用于其他需要人工标定的相机。
部分参考资料
https://wiki.ros.org/image_pipeline/CameraInfo
http://wiki.ros.org/camera_calibration
http://wiki.ros.org/camera_calibration/Tutorials/StereoCalibration