Bootstrap

【杂七杂八的东西】ROSBAG:用python按时间戳提取bag中的图像

1. ROSBAG提取制定topic图像

跟着朋友学习了一下如何在bag中提取带有时间戳的图像(我们主要取的是单通道的深度图像),感觉在ROS机器人中使用的非常普遍,闲话不多说,直接上完整的python代码。如果想看详细的ROSBAG解释的话可以看后面的debug细节。

#coding:utf-8

import rosbag
import cv2
from cv_bridge import CvBridge

path='/nfs/xmq/depth_pic/'        # 存储图像的地址

bag_file = '0115d.bag'
bag = rosbag.Bag(bag_file, "r")   # 载入bag文件
bag_data = bag.read_messages()    # 利用迭代器返回三个值:{topic标签, msg数据, t时间戳}

bridge = CvBridge()
for topic, msg, t in bag_data:
    if topic == "/camera/depth/image_rect_raw":
        cv_image = bridge.imgmsg_to_cv2(msg, "16UC1")  # 这里要注意图像的格式 
        print(cv_image.shape)                          # 避免图像是Nonetype

        timestr = "%.6f" %  msg.header.stamp.to_sec()  # %.6f表示小数点后带有6位,可根据精确度需要修改;
        image_name = timestr+ ".jpg"                   # 图像命名:时间戳.jpg
        cv2.imwrite(path+ image_name, cv_image)        # 保存;

2. 详细的ROSBAG解释和Debug细节

2.1 读取bag信息

我们来看一下bag中的到底有什么,读取代码如下:

info = bag.get_type_and_topic_info() # 或者在命令行中输入rosbag info *.bag 
print(info)

可以得到如下的信息:

TypesAndTopicsTuple(
	msg_types={
		'sensor_msgs/Image': '060021388200f6f0f447d0fcd9c64743'}, 
		topics={
			'/camera/color/image_raw': 
			TopicTuple(
				msg_type='sensor_msgs/Image', 
				message_count=1420, 
				connections=1, 
				frequency=29.975800976251225), 
			'/camera/depth/image_rect_raw': 
			TopicTuple(
				msg_type='sensor_msgs/Image', 
				message_count=1420, 
				connections=1, 
				frequency=29.99359267734554), 
			'/camera/infra1/image_rect_raw': 
				TopicTuple(msg_type='sensor_msgs/Image', 
				message_count=1420, 
				connections=1, 
				frequency=29.969161295854352)
				}
			)

我们需要关注的几个信息:

  • topics:一个bag数据中可能用很多个topic的数据,如果不挑选topic的话,read_messages()会将所有的topic都进行读取。如果想指定读取某一个topic,可以使用bag.read_messages('/camera/depth/image_rect_raw')
  • msg_type:数据的格式,我们的bag里面msg数据格式都是'sensor_msgs/Image',所以在用bridge的时候直接使用imgmsg_to_cv2(msg, "16UC1")函数即可。如果数据格式是'sensor_msgs/CompressedImage',则需要使用函数compressed_imgmsg_to_cv2(msg, "16UC1")
2.2 Debug记录:cv_bridge.core.CvBridgeError: [16UC1] is not a color format. but [bgr8] is. The conversion does not make sense

由于我们提取的不是三通道的彩色图像,我们在运行py文件的过程中出现了这个问题,查了大量的资料发现是因为图像编码格式的原因。"bgr8"等都是多通道图像格式,而"mono8""mono16"是单通道的图像格式,在读取的时候编码格式不对则报错,改正即可。注意!!! 但是单通道的一定要改为cv_image = bridge.imgmsg_to_cv2(msg, "16UC1"),而不是(msg, "mono16"),不要问我怎么知道的,就这一句就干了一下午,暴风哭泣。

Traceback (most recent call last):
	File "depth_copy.py", line 20, in <module>
		cv_image = bridge.imgmsg_to_cv2(msg, "bgr8")                    
	File "/opt/ros/kinetic/lib/python2.7/dist-packages/cv_bridge/core.py", line 184, in imgmsg_to_cv2
		raise CvBridgeError(e)
cv_bridge.core.CvBridgeError: [16UC1] is not a color format. but [bgr8] is. The conversion does not make sense

可以用"msg.format"来查看所有的图像编码格式,也可以去相机配置中查阅相关信息。

mono8: CV_8UC1, grayscale image
mono16: CV_16UC1, 16-bit grayscale image
bgr8: CV_8UC3, color image with blue-green-red color order
rgb8: CV_8UC3, color image with red-green-blue color order
bgra8: CV_8UC4, BGR color image with an alpha channel
rgba8: CV_8UC4, RGB color image with an alpha channel

2021年的第一篇博客,也是偷懒很久了。文章的最后,感谢各种博客和伙伴们的帮助,不胜感激,文中参考博客如下:

;