ROS 学习笔记(九)——rosbag 录制图像topic,提取 rgb 图和深度图

1. rosbag 命令行

rosbag
ros wiki:rosbagCommandline

在 ROS 系统中,可以使用 bag 文件来保存和恢复系统的运行状态,比如录制雷达和相机话题的 bag 包,然后回放进行数据处理。

rosbag 目前常用的命令如下:

  • 录制: rosbag record
    将指定话题录制到一个 bag 文件。
# 录制完保存 bag 包名称为 session1 + 时间戳.bag 格式:
rosbag record -o session1 <topic_names>

# 录制完保存为指定文件名session2.bag:
rosbag record -O session2.bag <topic_names>
  • 播放 rosbag play
    rosbag play 读取一个或多个 bag 文件的内容,并以时间同步的方式回放,时间同步基于接收消息的全局时间戳。回放开始后,会根据相对偏移时间发布消息。
    比如我先录制一个 bag1 包,等待一个小时,然后录制另一个 bag2 包,那我在一起回放 bag1 和 bag2 时,会先回放 bag1,然后等待 1 个小时才能回放 bag2。
# 在回放过程中按空格暂停,常见用法如下,回放单个 bag:
rosbag play record.bag
# 回放多个 bag,基于全局时间间隔播放:
rosbag play record1.bag record2.bag
#以录制的一半频率回放:
rosbag play -r 0.5 --pause record.bag
# 指定回放频率,默认 100HZ:
rosbag play --clock --hz=200 record.bag
# 循环播放:
rosbag play -l record.bag
  • 压缩:rosbag compress
# 指定压缩格式为 lz4,默认的压缩格式是 bz2
rosbag compress --lz4 xxx.bag
# 解压缩
rosbag decompress xxx.bag
  • rosbag info
    显示包文件内容的可读摘要,包括开始和结束时间,主题及其类型,消息计数、频率以及压缩统计信息。
rosbag info name.bag
# 输出 YAML 格式的信息:
rosbag info -y name.bag

2. rosbag 图像数据解析(python)

rosbag/Code API
python API Documentation

用 Azure-kinect相机,采用如下命令采集了一段rgb 图像和深度图话题的 rosbag。

rosbag record -O image.bag /rgb/image_raw /depth_to_rgb/image_raw

现需要将其解析为 rgb 图像和深度图的灰度图。

参考:
guikunchen/converter-between-rosbag-and-images给出了rosbag 与图像之间的相互转换完整的解决方案。

get_depth_rgb_from_rosbag.py 程序(有改动)如下:

import numpy
import rosbag
import cv2
import os
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
from cv_bridge import CvBridgeError
rgb_path = '/path/to/save/re-edit-bag/rgb/'# absolute path of extracted rgb images
depth_path = '/path/to/save/re-edit-bag/depth/'# absolute path of extracted depth images
bridge = CvBridge()
with rosbag.Bag('/path/to/image.bag', 'r') as bag:
	num = 1
    for topic,msg,t in bag.read_messages():
        
        if topic == "/depth_to_rgb/image_raw": 
            cv_image = bridge.imgmsg_to_cv2(msg, '32FC1')
            cv_image = cv_image * 255  # 不知为何转化的深度图显示不出来。将其乘以 255 才能看到显示效果.

            # timestr = "%.8f" %  msg.header.stamp.to_sec() # 时间戳命名
            # image_name = timestr + '.png'# an extension is necessary
            image_name = str(num) + '.png'# 编号命名
            cv2.imwrite(depth_path + image_name, cv_image)  
            # 实际应用可直接保存为 numpy array
            # np.save(depth_path + image_name, cv_image)  
            print(depth_path + image_name)
        if topic == "/rgb/image_raw": 
            cv_image = bridge.imgmsg_to_cv2(msg, "bgr8")
            timestr = "%.8f" %  msg.header.stamp.to_sec()
            image_name = str(num) + '.png'
            cv2.imwrite(rgb_path + image_name, cv_image)
       num += 1

正确设置文件路径,运行此代码即可。

注,相机采集的深度图是 32 位的浮点数。经bridge.imgmsg_to_cv2(msg, '32FC1')转换得到是以米为单位的深度数值。而cv2.imwrite()写入的则是 0-255 的数值,因此深度值都被取整了,导致直接保存的图片全黑了。显然简单的乘以 255 的处理方法会丢失大量的有效信息。

这个链接一定程度上解决了这个问题。核心代码如下:

# cv_image = self.bridge.imgmsg_to_cv2(msg_depth, "32FC1")
# depth_array = np.array(cv_image, dtype=np.float32)
# "passthrough"表示默认格式,即可得到np.float32,无需np.array语句。
depth_array = self.bridge.imgmsg_to_cv2(depth_data, "passthrough") # 此句等同于前两行
# Normalize the depth image to fall between 0 (black) and 1 (white)
cv2.normalize(depth_array, depth_array, 0, 1, cv2.NORM_MINMAX)

cv2.imwrite("depth.png", depth_array*255)

你可能感兴趣的:(Ros)