sensor_msgs/CameraInfo Message理解

Apriltag视觉定位中相机标定详解
本文详细解析了在使用apriltag进行视觉定位时,如何通过传感器消息CameraInfo来标定相机。包括了解释每个参数的意义,如相机内参矩阵K、畸变参数D等。

在使用apriltag进行视觉定位的时候需要对相机进行标定,apriltag_ros会订阅sensor_msgs/CameraInfo话题。/camera/camera_info话题的一帧数据如下:
在这里插入图片描述
里面的每一个参数代表着什么意思呢,接下来我将对这些参数进行解释。

  • header:标准消息头
    seq:序列ID,连续递增的ID号
    stamp:两个时间戳
    frame_id:与此数据相关联的帧ID
  • height:图像尺寸,height代表高度,(height*width)相机的分辨率,以像素为单位
  • width:图像尺寸,width代表宽度,(height*width)相机分辨率,以像素为单位
  • distortion_model:指定了相机畸变模型,对于大多数相机,"plumb_bob"简单的径向和切向畸变模型就足够了
  • D:畸变参数,取决于畸变模型,(k1, k2, t1, t2, k3),(我的这个usb相机号称是无畸变相机,但通过标定结果可以看出来还是存在畸变的,是不是被商家坑了,哈哈哈)
  • K:相机内参矩阵,使用焦距(fx, fy)和主点坐标(cx, cy),单位为像素,内参矩阵可以将相机坐标中的3D点投影到2D像素坐标
    在这里插入图片描述
  • R:旋转矩阵,将相机坐标系统对准理想的立体图像平面,使两张立体图像中的极线平行
你已经成功启动了相机,并且发布了ROS中常见的图像和相机信息话题。接下来,你需要进行以下关键步骤来处理图像数据、标定相机以及完成手眼标定(特别是你在eye-in-hand模式下使用机械臂)。 --- ## 🧰 当前已发布的话题说明 | Topic Name | Type | 用途 | |------------|------|------| | `/ascamera/depth0/camera_info` | `sensor_msgs/CameraInfo` | 深度相机内参(焦距、畸变系数等) | | `/ascamera/depth0/image_raw` | `sensor_msgs/Image` | 原始深度图像(16UC1或32FC1格式) | | `/ascamera/depth0/points` | `sensor_msgs/PointCloud2` | 点云数据(XYZRGB点) | | `/ascamera/mjpeg0/compressed` | `sensor_msgs/CompressedImage` | MJPEG压缩的RGB图像流 | | `/ascamera/rgb0/camera_info` | `sensor_msgs/CameraInfo` | RGB相机内参 | | `/ascamera/rgb0/image` | `sensor_msgs/Image` | 原始RGB图像 | --- ## ✅ 接下来的操作流程 ### 1. **查看图像(可选)** 使用 `rqt_image_view` 查看图像是否正常: ```bash rosrun rqt_image_view rqt_image_view ``` 选择 `/ascamera/rgb0/image` 或 `/ascamera/depth0/image_raw` 查看图像。 --- ### 2. **同步RGB与Depth图像(可选但推荐)** 如果你需要对RGB图像中的物体做3D位置估计,建议使用 `message_filters` 同步RGB图像与Depth图像。 示例代码片段(Python): ```python import rospy from sensor_msgs.msg import Image, CameraInfo from cv_bridge import CvBridge import message_filters rospy.init_node("image_sync_node") bridge = CvBridge() def callback(rgb_msg, depth_msg): rgb = bridge.imgmsg_to_cv2(rgb_msg, "bgr8") depth = bridge.imgmsg_to_cv2(depth_msg, desired_encoding="16UC1") # 处理图像... rgb_sub = message_filters.Subscriber("/ascamera/rgb0/image", Image) depth_sub = message_filters.Subscriber("/ascamera/depth0/image_raw", Image) ts = message_filters.ApproximateTimeSynchronizer([rgb_sub, depth_sub], queue_size=10, slop=0.1) ts.registerCallback(callback) rospy.spin() ``` --- ### 3. **获取相机内参** 从 `/ascamera/rgb0/camera_info` 和 `/ascamera/depth0/camera_info` 获取相机矩阵(K)和畸变系数(D): ```bash rostopic echo /ascamera/rgb0/camera_info ``` 你会看到如下字段: - `K`: 相机矩阵 `[fx, 0, cx, 0, fy, cy, 0, 0, 1]` - `D`: 畸变系数 `[k1, k2, p1, p2, k3]` 这些参数可用于后续的角点提取、solvePnP等操作。 --- ### 4. **棋盘格角点检测(用于标定)** 使用OpenCV检测RGB图像中的棋盘格角点: ```python import cv2 import numpy as np pattern_size = (9, 7) # 棋盘格角点数 square_size = 20 # 单位:毫米 def image_callback(img_msg): img = bridge.imgmsg_to_cv2(img_msg, "bgr8") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, corners = cv2.findChessboardCorners(gray, pattern_size, None) if ret: # 保存世界坐标和图像坐标 objp = np.zeros((pattern_size[0]*pattern_size[1], 3), np.float32) objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)*square_size # 存储 objp 和 corners ``` --- ### 5. **使用solvePnP计算标定板在相机坐标系下的位姿** ```python ret, rvec, tvec = cv2.solvePnP(objp, corners, camera_matrix, dist_coeffs) ``` 得到标定板相对于相机的旋转和平移向量。 --- ### 6. **获取机械臂末端位姿(TCP Pose)** 假设你使用的是UR机器人,可以通过如下方式获取当前TCP位姿: ```bash rostopic echo /joint_states ``` 或者直接调用SDK获取TCP位姿(如使用 `urx` 库): ```python import urx rob = urx.Robot("192.168.1.1") pose = rob.getl() # x, y, z, rx, ry, rz ``` 将此位姿转换为齐次变换矩阵。 --- ### 7. **进行手眼标定(Eye-in-Hand)** 收集多组 `R_gripper2base`, `t_gripper2base` 和 `R_target2cam`, `t_target2cam` 数据后,使用 OpenCV 的 `cv2.calibrateHandEye()` 进行手眼标定,得到 `T_cam2gripper`。 --- ### 8. **保存标定结果** 将最终的手眼变换矩阵保存为 `.yaml` 文件,供后续视觉引导抓取使用。 --- ## 🧾 总结流程图 ``` 获取图像 → 提取角点 → 计算标定板位姿 → 获取机械臂末端位姿 → 手眼算法 → 得到相机到末端变换矩阵 → 保存并验证 ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值