在gazebo中进行相机标定

  • 相机标定原理
    • 相机标定意义
    • 相机标定原理
      • 相机标定参数
      • 相关坐标系
        • 世界坐标系
        • 相机坐标系
        • 像素坐标系、图像坐标系
      • 相机坐标系转换为世界坐标系
      • 像素坐标系转换为图像坐标系
      • 相机坐标系转换为图像坐标系
      • 世界坐标系转换为像素坐标系
    • 举个实例
  • 用ROS camera_calibration 功能包 在gazebo中进行 相机校准
    • gazebo .world 文件
    • 建立 相机 的 xacro 模型 文件
    • 建立棋盘
    • 启动 仿真 环境
    • 进行较准
      • 运行校准程序
      • 棋盘变动位置及姿态
      • 校准结果
    • 至此校准完成

相机标定原理

相机标定意义

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

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

相机标定原理

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

相机标定参数

具体参数如下:

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

相关坐标系

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

世界坐标系

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

相机坐标系

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

像素坐标系、图像坐标系


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

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

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

转换方程为:

其中R为33的旋转矩阵,t为31的平移矢量

这个就是外参

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


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

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

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

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

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

举个实例

现以NiKon D700相机为例进行求解其内参数矩阵:
就算大家身边没有这款相机也无所谓,可以在网上百度一下,很方便的就知道其一些参数——
焦距 f = 35mm 最高分辨率:4256×2832 传感器尺寸:36.0×23.9 mm
根据以上定义可以有:
u0= 4256/2 = 2128 v0= 2832/2 = 1416 dx = 36.0/4256 dy = 23.9/2832
fx = f/dx = 4137.8 fy = f/dy = 4147.3

用ROS camera_calibration 功能包 在gazebo中进行 相机校准

下面 在 gazebo 中建立一个 可以校准的 仿真 环境 。 世界、相机、棋盘。

gazebo .world 文件

在gazebo 中 建立 一个 0 重力的 world 文件

<?xml version="1.0" ?>
<sdf version="1.4"><world name="default"><include><uri>model://ground_plane</uri></include><include><uri>model://sun</uri></include><physics type="ode"><gravity>0 0 0</gravity><real_time_update_rate>1000.0</real_time_update_rate></physics></world>
</sdf>

上面 gravity 标签 这样设置 即 为 正常 重力

<gravity>0 0 -9.81</gravity>

建立 相机 的 xacro 模型 文件

<?xml version="1.0" ?>
<robot name="simple_camera" xmlns:xacro="http://www.ros.org/wiki/xacro"><link name="world"><origin xyz="0.0 0.0 0.0"/>  </link><joint name="camera_joint" type="fixed"><parent link="world"/><child link="camera_link"/><origin rpy="0.0 1.5708 1.5708" xyz="0 0.0 0.5"/>   rpy这样设置 垂直向下拍摄  xyz 这样设置 高度0.5m</joint><link name="camera_link"><visual><origin xyz="0 0 0.0" rpy="0 0 0"/><geometry><box size="0.03 0.01 0.01"/>  这个 尺寸 大小 无所谓</geometry></visual><inertial><mass value="10" /><origin xyz="0 0 0" rpy="0 0 0"/><inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6" /></inertial></link><!-- camera simulator plug-in --><gazebo reference="camera_link">    加载 相机 的 插件  下面 配置相机参数<sensor type="camera" name="camera"><update_rate>30.0</update_rate><camera name="camera"><horizontal_fov>0.6</horizontal_fov>   相机 水平视场角<image><width>640</width>  像素宽度  u<height>480</height> 像素高度 v<format>R8G8B8</format></image><clip><near>0.005</near>    最近拍摄距离<far>0.9</far>  最远拍摄距离</clip><noise>   // 相机噪声<type>gaussian</type><mean>0.0</mean><stddev>0.000</stddev></noise></camera><plugin name="camera_controller" filename="libgazebo_ros_camera.so"><alwaysOn>true</alwaysOn><updateRate>0.0</updateRate><cameraName>simple_camera</cameraName><imageTopicName>image_raw</imageTopicName><cameraInfoTopicName>camera_info</cameraInfoTopicName><frameName>camera_link</frameName>、后面需要 看看 求 得的 和这里一致不 一致   应该 会 差些  更 该 这里值 再看看<distortionK1>0.0</distortionK1>   这里的畸变参数均设置为 0   K是 横向畸变参数  <distortionK2>0.0</distortionK2>   这里的畸变参数均设置为 0  <distortionK3>0.0</distortionK3>   这里的畸变参数均设置为 0  <distortionT1>0.0</distortionT1>   这里的畸变参数均设置为 0  T是 切向畸变参数<distortionT2>0.0</distortionT2>   这里的畸变参数均设置为 0  </plugin></sensor></gazebo>  </robot>

建立棋盘

下面做一个黑白相间的棋盘 做 标定用。

做好后 是 下面这样的

棋盘的 sdf 模型 文件 如下

<?xml version='1.0'?>
<sdf version="1.4">
<model name="checkerboard"><pose>0 0 0 0 0 0</pose><static>false</static><link name="checkerboard"><pose>0.0 0.0 0.0 0.0 0.0 0.0</pose><inertial><mass>0.01</mass><inertia> <!-- interias are tricky to compute --><!-- http://answers.gazebosim.org/question/4372/the-inertia-matrix-explained/ --><ixx>0.083</ixx>       <!-- for a box: ixx = 0.083 * mass * (y*y + z*z) --><ixy>0.0</ixy>         <!-- for a box: ixy = 0 --><ixz>0.0</ixz>         <!-- for a box: ixz = 0 --><iyy>0.083</iyy>       <!-- for a box: iyy = 0.083 * mass * (x*x + z*z) --><iyz>0.0</iyz>         <!-- for a box: iyz = 0 --><izz>0.083</izz>       <!-- for a box: izz = 0.083 * mass * (x*x + y*y) --></inertia></inertial><collision name="collision"><geometry><box><size>0.02 0.02 0.005</size></box></geometry></collision><visual name="sqr11"><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr12"><pose>0.02 0.0 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr13"><pose>0.04 0.0 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr14"><pose>0.06 0.0 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr15"><pose>0.08 0.0 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr16"><pose>0.10 0.0 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr17"><pose>0.12 0.0 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr18"><pose>0.14 0.0 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr21"><pose>0.0 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr31"><pose>0.0 0.04 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr32"><pose>0.02 0.04 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr33"><pose>0.04 0.04 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr34"><pose>0.06 0.04 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr35"><pose>0.08 0.04 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr36"><pose>0.10 0.04 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr37"><pose>0.12 0.04 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr38"><pose>0.14 0.04 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr51"><pose>0.0 0.08 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr52"><pose>0.02 0.08 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr53"><pose>0.04 0.08 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr54"><pose>0.06 0.08 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr55"><pose>0.08 0.08 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr56"><pose>0.10 0.08 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr57"><pose>0.12 0.08 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr58"><pose>0.14 0.08 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr71"><pose>0.0 0.12 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr72"><pose>0.02 0.12 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr73"><pose>0.04 0.12 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr74"><pose>0.06 0.12 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr75"><pose>0.08 0.12 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr76"><pose>0.10 0.12 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr77"><pose>0.12 0.12 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr78"><pose>0.14 0.12 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr21"><pose>0.0 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr22"><pose>0.02 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr23"><pose>0.04 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual> <visual name="sqr24"><pose>0.06 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr25"><pose>0.08 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr26"><pose>0.10 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr27"><pose>0.12 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr28"><pose>0.14 0.02 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr41"><pose>0.0 0.06 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr42"><pose>0.02 0.06 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr43"><pose>0.04 0.06 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual> <visual name="sqr44"><pose>0.06 0.06 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr45"><pose>0.08 0.06 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr46"><pose>0.10 0.06 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr47"><pose>0.12 0.06 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr48"><pose>0.14 0.06 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr61"><pose>0.0 0.10 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr62"><pose>0.02 0.10 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr63"><pose>0.04 0.10 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual> <visual name="sqr64"><pose>0.06 0.10 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr65"><pose>0.08 0.10 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr66"><pose>0.10 0.10 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr67"><pose>0.12 0.10 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>1 1 1 1</ambient><diffuse>1 1 1 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual><visual name="sqr68"><pose>0.14 0.10 0.0 0.0 0.0 0.0</pose><geometry><box><size>0.02 0.02 0.005</size></box></geometry><material><ambient>0 0 0 1</ambient><diffuse>0 0 0 1</diffuse><specular>0.1 0.1 0.1 1</specular><emissive>0 0 0 0</emissive></material></visual></model>
</sdf>

至此 在 gazebo 中的 world 和 相机 模型 棋盘 模型 已 编辑 完成了

下面 写 好launch 文件 加载 以上内容

launch 文件 如下

<launch><!-- the following is a copy of empty_world.launch--><!-- these are the arguments you can pass this launch file, for example paused:=true --><arg name="paused" default="false"/><arg name="use_sim_time" default="true"/><arg name="extra_gazebo_args" default=""/><arg name="gui" default="true"/><arg name="headless" default="false"/><arg name="debug" default="false"/><arg name="physics" default="ode"/><arg name="verbose" default="false"/><arg name="world_name" value="$(find simple_camera_model)/simple_camera.world"/><!--arg name="world_name" default="worlds/empty.world"/--> <!-- Note: the world_name is with respect to GAZEBO_RESOURCE_PATH environmental variable --><!-- set use_sim_time flag --><group if="$(arg use_sim_time)"><param name="/use_sim_time" value="true" /></group><!-- set command arguments --><arg unless="$(arg paused)" name="command_arg1" value=""/><arg     if="$(arg paused)" name="command_arg1" value="-u"/><arg unless="$(arg headless)" name="command_arg2" value=""/><arg     if="$(arg headless)" name="command_arg2" value="-r"/><arg unless="$(arg verbose)" name="command_arg3" value=""/><arg     if="$(arg verbose)" name="command_arg3" value="--verbose"/><arg unless="$(arg debug)" name="script_type" value="gzserver"/><arg     if="$(arg debug)" name="script_type" value="debug"/><!-- start gazebo server--><node name="gazebo" pkg="gazebo_ros" type="$(arg script_type)" respawn="false" output="screen"args="$(arg command_arg1) $(arg command_arg2) $(arg command_arg3) -e $(arg physics) $(arg extra_gazebo_args) $(arg world_name)" /><!-- start gazebo client --><group if="$(arg gui)"><node name="gazebo_gui" pkg="gazebo_ros" type="gzclient" respawn="false" output="screen"/></group><!-- here we add our own models to the simulation-->  <param name="robot_description" command="$(find xacro)/xacro.py '$(find simple_camera_model)/simple_camera_model.xacro'" /><!-- Spawn a robot into Gazebo -->
<node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" args="-param robot_description -urdf -model simple_camera" /><node name="spawn_sdf" pkg="gazebo_ros" type="spawn_model" args="-file $(find exmpl_models)/small_checkerboard/small_checkerboard.sdf -sdf -model small_checkerboard -x -0.03 -y -0.03 -z 0.2" /></launch>

启动 仿真 环境

启动 该 launch文件 出现如下 场景 一个 立方体(模拟相机) 悬在棋盘正上方

此时 相机发布 了 如下 信息

/simple_camera/camera_info 这里有一条 这个
查看 该 消息 内容 如下

之后 查查 每个 向量的 意思
初步猜测
D 是 5个 元素 和 畸变向量 对应
K 是 9个元素 可能 是 下面的那个矩阵

P 是 12 个元素 和内参矩阵对应

/simple_camera/image_raw 这个 是 相机 发布的 图像 信息 可以看下

rosrun image_view image_view image:=/simple_camera/image_raw

就是相机拍 着 的 棋盘

进行较准

下面的工作就是要运行校准程序

相机校准在ROS中主要运用 camera_calibration 功能包

camera_calibration ROS WIKI

这个功能包在装ROS的时候一般就装好了,不需要手动去安装。可以看

这个路径下 是否 有 cameracalibrator.py 这个文件

把这文件的代码粘在下面:

import cv2
import functools
import message_filters
import os
import rospy
from camera_calibration.camera_calibrator import OpenCVCalibrationNode
from camera_calibration.calibrator import ChessboardInfo, Patterns
from message_filters import ApproximateTimeSynchronizerdef main():from optparse import OptionParser, OptionGroupparser = OptionParser("%prog --size SIZE1 --square SQUARE1 [ --size SIZE2 --square SQUARE2 ]",description=None)parser.add_option("-c", "--camera_name",type="string", default='narrow_stereo',help="name of the camera to appear in the calibration file")group = OptionGroup(parser, "Chessboard Options","You must specify one or more chessboards as pairs of --size and --square options.")group.add_option("-p", "--pattern",type="string", default="chessboard",help="calibration pattern to detect - 'chessboard', 'circles', 'acircles'")group.add_option("-s", "--size",action="append", default=[],help="chessboard size as NxM, counting interior corners (e.g. a standard chessboard is 7x7)")group.add_option("-q", "--square",action="append", default=[],help="chessboard square size in meters")parser.add_option_group(group)group = OptionGroup(parser, "ROS Communication Options")group.add_option("--approximate",type="float", default=0.0,help="allow specified slop (in seconds) when pairing images from unsynchronized stereo cameras")group.add_option("--no-service-check",action="store_false", dest="service_check", default=True,help="disable check for set_camera_info services at startup")parser.add_option_group(group)group = OptionGroup(parser, "Calibration Optimizer Options")group.add_option("--fix-principal-point",action="store_true", default=False,help="fix the principal point at the image center")group.add_option("--fix-aspect-ratio",action="store_true", default=False,help="enforce focal lengths (fx, fy) are equal")group.add_option("--zero-tangent-dist",action="store_true", default=False,help="set tangential distortion coefficients (p1, p2) to zero")group.add_option("-k", "--k-coefficients",type="int", default=2, metavar="NUM_COEFFS",help="number of radial distortion coefficients to use (up to 6, default %default)")group.add_option("--disable_calib_cb_fast_check", action='store_true', default=False,help="uses the CALIB_CB_FAST_CHECK flag for findChessboardCorners")parser.add_option_group(group)options, args = parser.parse_args()if len(options.size) != len(options.square):parser.error("Number of size and square inputs must be the same!")if not options.square:options.square.append("0.108")options.size.append("8x6")boards = []for (sz, sq) in zip(options.size, options.square):size = tuple([int(c) for c in sz.split('x')])boards.append(ChessboardInfo(size[0], size[1], float(sq)))if options.approximate == 0.0:sync = message_filters.TimeSynchronizerelse:sync = functools.partial(ApproximateTimeSynchronizer, slop=options.approximate)num_ks = options.k_coefficientscalib_flags = 0if options.fix_principal_point:calib_flags |= cv2.CALIB_FIX_PRINCIPAL_POINTif options.fix_aspect_ratio:calib_flags |= cv2.CALIB_FIX_ASPECT_RATIOif options.zero_tangent_dist:calib_flags |= cv2.CALIB_ZERO_TANGENT_DISTif (num_ks > 3):calib_flags |= cv2.CALIB_RATIONAL_MODELif (num_ks < 6):calib_flags |= cv2.CALIB_FIX_K6if (num_ks < 5):calib_flags |= cv2.CALIB_FIX_K5if (num_ks < 4):calib_flags |= cv2.CALIB_FIX_K4if (num_ks < 3):calib_flags |= cv2.CALIB_FIX_K3if (num_ks < 2):calib_flags |= cv2.CALIB_FIX_K2if (num_ks < 1):calib_flags |= cv2.CALIB_FIX_K1pattern = Patterns.Chessboardif options.pattern == 'circles':pattern = Patterns.Circleselif options.pattern == 'acircles':pattern = Patterns.ACircleselif options.pattern != 'chessboard':print('Unrecognized pattern %s, defaulting to chessboard' % options.pattern)if options.disable_calib_cb_fast_check:checkerboard_flags = 0else:checkerboard_flags = cv2.CALIB_CB_FAST_CHECKrospy.init_node('cameracalibrator')node = OpenCVCalibrationNode(boards, options.service_check, sync, calib_flags, pattern, options.camera_name,checkerboard_flags=checkerboard_flags)rospy.spin()if __name__ == "__main__":try:main()except Exception as e:import tracebacktraceback.print_exc()

wiki的介绍和 代码 最上面 参数 的介绍 一样,有一些必须要有的参数 设置

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

运行校准程序

运行 这个 功能包 根据上面参数 设定, 具体指令如下:

rosrun camera_calibration cameracalibrator.py --size 7x6 --square 0.01 image:=/simple_camera/image_raw camera:=/simple_camera

出现新界面

终端显示

这说明采集到了一个 样本

棋盘变动位置及姿态

棋盘变位置和姿态后就会 自动 再采集 样本

让棋盘随机 移动 旋转 生成随机姿态,约束于保持在相机视野内。棋盘垂直,水平移动,并以任意倾斜角度倾斜。棋盘格姿势每次持续0.5秒。使用以下命令可以不断改变标定板的位置
功能代码如下

#include <ros/ros.h>
#include <gazebo_msgs/ModelState.h>
#include <geometry_msgs/Pose.h>
#include <gazebo_msgs/SetModelState.h>
#include <math.h>
#include <iostream>
#include <string>
using namespace std; int main(int argc, char **argv) {ros::init(argc, argv, "move_gazebo_model");ros::NodeHandle n;ros::ServiceClient client = n.serviceClient<gazebo_msgs::SetModelState>("/gazebo/set_model_state");gazebo_msgs::SetModelState set_model_state_srv;gazebo_msgs::ModelState des_model_state;geometry_msgs::Twist twist;int ans;bool do_skew=false;twist.linear.x = 0.0;twist.linear.y = 0.0;twist.linear.z = 0.0;twist.angular.x = 0.0;twist.angular.y = 0.0;twist.angular.z = 0.0;geometry_msgs::Pose pose;geometry_msgs::Quaternion quat;double x_bias = -0.03;double y_bias = -0.03;double z_bias = 0.2;double x,y,z;double dx = 0.1;double dy = 0.1;double dz = 0.15;pose.position.x = x;pose.position.y = y;pose.position.z = z;quat.x = 0.0;quat.y = 0.0;quat.z = 0.0;quat.w = 1.0;pose.orientation= quat;des_model_state.model_name = "small_checkerboard"; des_model_state.pose = pose;des_model_state.twist = twist;des_model_state.reference_frame = "world";double qx,qy,qz,qw;//do random displacements and skews//cout<<"do skews? (0,1): ";//cin>>ans;//if (ans) do_skew=true;do_skew=true;while(ros::ok()) {qx = 0.2*(( (rand()%100)/100.0)-0.5); qy = 0.2*(( (rand()%100)/100.0)-0.5);qz = 0.2*(( (rand()%100)/100.0)-0.5);qw =  0.5; x = x_bias + dx*((rand()%100)/100.0-0.5); y = y_bias + dy*((rand()%100)/100.0-0.5); z = z_bias + dz*((rand()%100)/100.0-0.5); double norm = sqrt(qx*qx+qy*qy+qz*qz+qw*qw);quat.x = qx/norm;quat.y = qy/norm;quat.z = qz/norm;quat.w = qw/norm;cout<<"qx, qy, qz, qw= "<<quat.x<<", "<<quat.y<<", "<<quat.z<<", "<<quat.w<<endl;cout<<"x,y,z = "<<x<<", "<<y<<", "<<z<<endl;if(do_skew) pose.orientation= quat;pose.position.x = x;pose.position.y = y;pose.position.z = z;des_model_state.pose = pose;set_model_state_srv.request.model_state = des_model_state;client.call(set_model_state_srv);ros::spinOnce();//cout<<"enter 1 to advance, <1 to quit: ";//cin>>ans;//if (ans<1) return 0;ros::Duration(0.5).sleep();}return 0;
}

运行这个功能包

rosrun example_camera_calibration move_calibration_checkerboard

校准结果

看 校准 那个 终端 样本就自动往上 增加了

这个 图像 和实际 一样 棋盘在不断变换 着 位置 和姿态 XY Size 进度 条也会 增加

当 CALIBRATE 这个按扭变成 这个 颜色 说明 样本 采集 够了

点击 CALIBRATE 按钮后 下面的SAVE 也会 变色

校准的终端也会输出 求得的 相机的 内参 和 畸变参数

点击 SAVE 后 会保存在 ~/.ros/camera_info中的 simple_camera.yaml 文件

在打印 相机此时相机的信息 会是 校准后的参数

至此校准完成

相机标定原理 用ROS camera_calibration 功能包 在gazebo中进行 相机校准相关推荐

  1. 非常详细的相机标定原理、步骤(一)

    目录 一.什么是相机标定 二.坐标系 1.世界坐标系(word Coordinate) 2.相机坐标系(camera coordinate) 3.世界坐标系到相机坐标系转换 三.总结: 非常详细的相机 ...

  2. 相机标定 matlab opencv ROS三种方法标定步骤(3)

    三 ,  ROS 环境下 如何进行相机标定 刚开始做到的时候遇到一些问题没有记录下来,现在回头写的时候都是没有错误的结果了,首先使用ROS标定相机, 要知道如何查看节点之间的流程图  rosrun r ...

  3. 相机标定 matlab opencv ROS三种方法标定步骤(1)

    一 . 理解摄像机模型,网上有很多讲解的十分详细,在这里我只是记录我的整合出来的资料和我的部分理解 计算机视觉领域中常见的三个坐标系:图像坐标系,相机坐标系,世界坐标系,实际上就是要用矩阵来表 示各个 ...

  4. 相机标定 matlab opencv ROS三种方法标定步骤(2)

    二  ubuntu下Opencv的相机标定 一般直接用Opencv的源码就可以进行相机的标定,但是可能只是会实现结果,却不懂实现的过程,我也是模模糊糊的看了<计算机视觉中的多视图几何>以及 ...

  5. ros创建功能包和编译过程问题处理

    文章目录 1. 创建工作空间和功能包 2.新建cpp文件 3.修改CMakeLists.txt 4.编译问题 4.1 Could NOT find rospy (missing: rospy_DIR) ...

  6. 【计算机视觉】相机标定原理(像素点与三维坐标点的转换)

    一.相机标定概述 相机标定目的 计算机视觉的任务之一:从相机获取的图像信息出发计算三维空间中物体的几何信息,并由此重建和识别物体. 相机标定内容 空间物体表面某点的三维几何位置与其在图像中对应点之间的 ...

  7. 相机标定原理_第二期直播《相机标定的基本原理与经验分享》精彩回录

    作者:齐小凡 来源:第二期直播<相机标定的基本原理与经验分享>精彩回录 大家好,本公众号现已开启线上视频公开课,主讲人通过B站直播间,对3D视觉领域相关知识点进行讲解,并在微信群内完成答疑 ...

  8. 1. 相机标定原理(学习笔记)

    相机标定(Camera Calibration)-学习笔记 文章目录 相机标定(Camera Calibration)-学习笔记 一.简介 二.原理 1. 坐标系 *coordinates* 2. 相 ...

  9. 视觉SLAM——针孔相机模型 相机标定原理 双目相机模型 深度相机对比

    前言 本博客为主要学习<视觉SLAM十四讲>第5讲.<机器人学的状态估计>第6章6.4.1透视相机.<多视图几何>第5章摄像头模型等SLAM内容的总结与整理. 主要 ...

最新文章

  1. 手机使用python操作图片文件
  2. Linux系统:软链接与硬链接的原理分析
  3. 【转载】android客服端+eps8266+单片机+路由器之远程控制系统
  4. 森拓品牌邀您参加第15届中国模具之都博览会
  5. 十大经典排序算法(动图演示)(转)
  6. Listary一款不只是程序员需要的软件
  7. Visio模具与模版
  8. 通过pcm音频数据计算分贝
  9. android打开超链接屏幕太小,手机屏幕太小,教你2种方法投屏到电脑上,小白也能轻松搞定!...
  10. Sablog-X v2.x 任意变量覆盖漏洞
  11. js 计算个人所得税
  12. PHP Session理解
  13. 十二星座谁最不会顾及别人感受?
  14. PC端如何使用ITunes无线连接ios手机
  15. mysql运维备份_MySQL运维经验
  16. 考研路上的那些一战二战三战成功与失败的故事系列之十三
  17. Java简单演示悲观锁
  18. 前后端交互之form表单和模板引擎
  19. pip安装遇到警告which is not on PATH 不修改site.py也可解决
  20. JQuery实现图片自动轮播左右切换鼠标移入

热门文章

  1. 北京航空大学计算机系余明明,于明明
  2. 一个Android大专应届生的2020
  3. 微信小程序-for循环为数组赋值
  4. hdu-1434-幸福列车
  5. sqlserver 怎么查看操作记录_抖音怎么查看访问记录,访客记录在哪里看的?
  6. 20202413 2022-2023-2 《网络与系统安全技术》实验五报告
  7. 拆分字符串中的图片和文字
  8. js模拟a标签下载,修改下载文件名称,jq上传文件
  9. php踩过的那些坑(5)浮点数计算
  10. LPCTSTR和LPCSTR和LPCWSTR的区别