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年的第一篇博客,也是偷懒很久了。文章的最后,感谢各种博客和伙伴们的帮助,不胜感激,文中参考博客如下:
- 在ubuntu上安装ROS教程:新手ubuntu16.04安装ROS
- ROSBAG教程:ROSBAG使用(二):使用python提取bag中的图像和点云
- ROSBAG教程:如何从rosbag提取图片(CompressedImage)之使用Python脚本文件
- ROSBAG教程:解析rosbag文件,得到带有时间戳的.jpg图片数据和.pcd点云数据