ROS学习 rosbag 转化为 mp4 格式视频
Posted wongHome
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ROS学习 rosbag 转化为 mp4 格式视频相关的知识,希望对你有一定的参考价值。
文章目录
写在前面
本文系统测试环境:
Ubuntu 18.04
ROS-melodic
一、文件准备
从 github 中下载对应的文件(或者直接复制文章最后的 rosbag2video.py
源码),并解压,然后将自己的 bag 文件(test.bag)放到文件夹内:
二、安装依赖
脚本运行需要安装依赖
sudo apt install ffmpeg
三、使用方法
rosbag2video.py
功能:利用ffmpeg
将 rosbag
(单位:s) 文件中的图像序列 (单位:s) 转换为 视频文件。
rosbag2video.py [--fps 25] [--rate 1] [-o outputfile] [-v] [-s] [-t topic] bagfile1 [bagfile2] ...
参数解释:
参数 | 英语解释 | 中文翻译 |
---|---|---|
–fps | Sets FPS value that is passed to ffmpeg. Default is 25. | 设置传递给ffmpeg的FPS的值. 默认是25. |
-h | Displays this help. | 显示帮助信息. |
–ofile (-o) | sets output file name. If no output file name (-o) is given the filename ‘[prefix]_[topic].mp4’ is used and default output codec is h264. Multiple image topics are supported only when -o option is _not used. ffmpeg will guess the format according to given extension. Compressed and raw image messages are supported with mono8 and bgr8/rgb8/bggr8/rggb8 formats. | 设置输出文件名. 如果没有设置输出文件名, 则默认是 [prefix]_[topic].mp4 命名, 并以h264 编码. 当 -o 没有被使用的时候,才会支持多个图像话题。 ffmpeg将根据给定的扩展猜测其格式。 支持压缩和原始的、mono8 和bgr8/rgb8/bggr8/rggb8 格式的图像消息。 |
–rate (-r) | You may slow down or speed up the video. Default is 1.0, that keeps the original speed. | 可以放慢或者加速视频。默认是1,也就是保持原始速度。 |
-s | Shows each and every image extracted from the rosbag file (cv_bride is needed). | 显示从rosbag文件提取的每帧图像。 |
–topic (-t) | Only the images from topic “topic” are used for the video output. | 指定用于视频输出的 相机"话题" 。 |
-v | Verbose messages are displayed. | 显示详细消息 |
–prefix (-p) | set a output file name prefix othervise ‘bagfile1’ is used (if -o is not set). | 设置输出文件名前缀,否则的话使用“ bagfile1”(也就是如果未设置-o ); |
–start | Optional start time in seconds. | 可选的开始时间 (单位:秒) |
–end | Optional end time in seconds. | 可选的结束时间 (单位:秒) |
四、举例:执行rosbag 转化为 mp4 格式视频的脚本
上面列出的参数可以不设置,也就是保持默认值,直接执行脚本文件:
python rosbag2video.py test.bag
经过一段时间的转换,就会得到对应的 mp4 视频文件:
五、参考链接
[1] mlaiacker. rosbag2video [EB/OL]. https://github.com/mlaiacker/rosbag2video, 2021-04-27/2022-10-18.
[2] hywmj. rosbag转化为.mp4格式视频 [EB/OL]. https://blog.csdn.net/wangmj_hdu/article/details/114130648, 2021-02-26/2022-10-18.
六、附录:rosbag2video.py 源码
#!/usr/bin/env python3
"""
rosbag2video.py
rosbag to video file conversion tool
by Abel Gabor 2019
baquatelle@gmail.com
requirements:
sudo apt install python3-roslib python3-sensor-msgs python3-opencv ffmpeg
based on the tool by Maximilian Laiacker 2016
post@mlaiacker.de"""
import roslib
#roslib.load_manifest('rosbag')
import rospy
import rosbag
import sys, getopt
import os
from sensor_msgs.msg import CompressedImage
from sensor_msgs.msg import Image
import cv2
import numpy as np
import shlex, subprocess
MJPEG_VIDEO = 1
RAWIMAGE_VIDEO = 2
VIDEO_CONVERTER_TO_USE = "ffmpeg" # or you may want to use "avconv"
def print_help():
print('rosbag2video.py [--fps 25] [--rate 1] [-o outputfile] [-v] [-s] [-t topic] bagfile1 [bagfile2] ...')
print()
print('Converts image sequence(s) in ros bag file(s) to video file(s) with fixed frame rate using',VIDEO_CONVERTER_TO_USE)
print(VIDEO_CONVERTER_TO_USE,'needs to be installed!')
print()
print('--fps Sets FPS value that is passed to',VIDEO_CONVERTER_TO_USE)
print(' Default is 25.')
print('-h Displays this help.')
print('--ofile (-o) sets output file name.')
print(' If no output file name (-o) is given the filename \\'<prefix><topic>.mp4\\' is used and default output codec is h264.')
print(' Multiple image topics are supported only when -o option is _not_ used.')
print(' ',VIDEO_CONVERTER_TO_USE,' will guess the format according to given extension.')
print(' Compressed and raw image messages are supported with mono8 and bgr8/rgb8/bggr8/rggb8 formats.')
print('--rate (-r) You may slow down or speed up the video.')
print(' Default is 1.0, that keeps the original speed.')
print('-s Shows each and every image extracted from the rosbag file (cv_bride is needed).')
print('--topic (-t) Only the images from topic "topic" are used for the video output.')
print('-v Verbose messages are displayed.')
print('--prefix (-p) set a output file name prefix othervise \\'bagfile1\\' is used (if -o is not set).')
print('--start Optional start time in seconds.')
print('--end Optional end time in seconds.')
class RosVideoWriter():
def __init__(self, fps=25.0, rate=1.0, topic="", output_filename ="", display= False, verbose = False, start = rospy.Time(0), end = rospy.Time(sys.maxsize)):
self.opt_topic = topic
self.opt_out_file = output_filename
self.opt_verbose = verbose
self.opt_display_images = display
self.opt_start = start
self.opt_end = end
self.rate = rate
self.fps = fps
self.opt_prefix= None
self.t_first=
self.t_file=
self.t_video=
self.p_avconv =
def parseArgs(self, args):
opts, opt_files = getopt.getopt(args,"hsvr:o:t:p:",["fps=","rate=","ofile=","topic=","start=","end=","prefix="])
for opt, arg in opts:
if opt == '-h':
print_help()
sys.exit(0)
elif opt == '-s':
self.opt_display_images = True
elif opt == '-v':
self.opt_verbose = True
elif opt in ("--fps"):
self.fps = float(arg)
elif opt in ("-r", "--rate"):
self.rate = float(arg)
elif opt in ("-o", "--ofile"):
self.opt_out_file = arg
elif opt in ("-t", "--topic"):
self.opt_topic = arg
elif opt in ("-p", "--prefix"):
self.opt_prefix = arg
elif opt in ("--start"):
self.opt_start = rospy.Time(int(arg))
if(self.opt_verbose):
print("starting at",self.opt_start.to_sec())
elif opt in ("--end"):
self.opt_end = rospy.Time(int(arg))
if(self.opt_verbose):
print("ending at",self.opt_end.to_sec())
else:
print("opz:", opt,'arg:', arg)
if (self.fps<=0):
print("invalid fps", self.fps)
self.fps = 1
if (self.rate<=0):
print("invalid rate", self.rate)
self.rate = 1
if(self.opt_verbose):
print("using ",self.fps," FPS")
return opt_files
# filter messages using type or only the opic we whant from the 'topic' argument
def filter_image_msgs(self, topic, datatype, md5sum, msg_def, header):
if(datatype=="sensor_msgs/CompressedImage"):
if (self.opt_topic != "" and self.opt_topic == topic) or self.opt_topic == "":
print("############# COMPRESSED IMAGE ######################")
print(topic,' with datatype:', str(datatype))
print()
return True;
if(datatype=="theora_image_transport/Packet"):
if (self.opt_topic != "" and self.opt_topic == topic) or self.opt_topic == "":
print(topic,' with datatype:', str(datatype))
print('!!! theora is not supported, sorry !!!')
return False;
if(datatype=="sensor_msgs/Image"):
if (self.opt_topic != "" and self.opt_topic == topic) or self.opt_topic == "":
print("############# UNCOMPRESSED IMAGE ######################")
print(topic,' with datatype:', str(datatype))
print()
return True;
return False;
def write_output_video(self, msg, topic, t, video_fmt, pix_fmt = ""):
# no data in this topic
if len(msg.data) == 0 :
return
# initiate data for this topic
if not topic in self.t_first :
self.t_first[topic] = t # timestamp of first image for this topic
self.t_video[topic] = 0
self.t_file[topic] = 0
# if multiple streams of images will start at different times the resulting video files will not be in sync
# current offset time we are in the bag file
self.t_file[topic] = (t-self.t_first[topic]).to_sec()
# fill video file up with images until we reache the current offset from the beginning of the bag file
while self.t_video[topic] < self.t_file[topic]/self.rate :
if not topic in self.p_avconv:
# we have to start a new process for this topic
if self.opt_verbose :
print("Initializing pipe for topic", topic, "at time", t.to_sec())
if self.opt_out_file=="":
out_file = self.opt_prefix + str(topic).replace("/", "_")+".mp4"
else:
out_file = self.opt_out_file
if self.opt_verbose :
print("Using output file ", out_file, " for topic ", topic, ".")
if video_fmt == MJPEG_VIDEO :
cmd = [VIDEO_CONVERTER_TO_USE, '-v', '1', '-stats', '-r',str(self.fps),'-c','mjpeg','-f','mjpeg','-i','-','-an',out_file]
self.p_avconv[topic] = subprocess.Popen(cmd, stdin=subprocess.PIPE)
if self.opt_verbose :
print("Using command line:")
print(cmd)
elif video_fmt == RAWIMAGE_VIDEO :
size = str(msg.width)+"x"+str(msg.height)
cmd = [VIDEO_CONVERTER_TO_USE, '-v', '1', '-stats','-r',str(self.fps),'-f','rawvideo','-s',size,'-pix_fmt', pix_fmt,'-i','-','-an',out_file]
self.p_avconv[topic] = subprocess.Popen(cmd, stdin=subprocess.PIPE)
if self.opt_verbose :
print("Using command line:")
print(cmd)
else :
print("Script error, unknown value for argument video_fmt in function write_output_video.")
exit(1)
# send data to ffmpeg process pipe
self.p_avconv[topic].stdin.write(msg.data)
# next frame time
self.t_video[topic] += 1.0/self.fps
def addBag(self, filename):
if self.opt_display_images:
from cv_bridge import CvBridge, CvBridgeError
bridge = CvBridge()
cv_image = []
if self.opt_verbose :
print("Bagfile: ".format(filename))
if not self.opt_prefix:
# create the output in the same folder and name as the bag file minu '.bag'
self.opt_prefix = bagfile[:-4]
#Go through the bag file
bag = rosbag.Bag(filename)
if self.opt_verbose :
print("Bag opened.")
# loop over all topics
for topic, msg, t in bag.read_messages(connection_filter=self.filter_image_msgs, start_time=self.opt_start, end_time=self.opt_end):
try:
if msg.format.find("jpeg")!=-1 :
if msg.format.find("8")!=-1 and (msg.format.find("rgb")!=-1 or msg.format.find("bgr")!=-1 or msg.format.find("bgra")!=-1 ):
if self.opt_display_images:
np_arr = np.fromstring(msg.data, np.uint8)
cv_image = cv2.imdecode(np_arr, cv2.CV_LOAD_IMAGE_COLOR)
self.write_output_video( msg, topic, t, MJPEG_VIDEO )
elif msg.format.find("mono8")!=-1 :
if self.opt_display_images:
np_arr = np.fromstring(msg.data, np.uint8)
cv_image = cv2.imdecode(np_arr, cv2.CV_LOAD_IMAGE_COLOR)
self.write_output_video( msg, topic, t, MJPEG_VIDEO )
elif msg.format.find("16UC1")!=-1 :
if self.opt_display_images:
np_arr = np.fromstring(msg.data, np.uint16)
cv_image = cv2.imdecode(np_arr, cv2.CV_LOAD_IMAGE_COLOR)
self.write_output_video( msg, topic, t, MJPEG_VIDEO )
else:
print('unsupported jpeg format:', msg.format, '.', topic)
# has no attribute 'format'
except AttributeError:
try:
pix_fmt=None
if msg.encoding.find("mono8")!=-1 or msg.encoding.find("8UC1")!=-1:
pix_fmt = "gray"
if self.opt_display_images:
cv_image = bridge.imgmsg_to_cv2(msg, "bgr8")
elif msg.encoding.find("bgra")!=-1 :
pix_fmt = "bgra"
if self.opt_display_images:
cv_image = bridge.imgmsg_to_cv2(msg, "bgr8")
elif msg.encoding.find("bgr8")!=-1 :
pix_fmt = "bgr24"
if self.opt_display_images:
cv_image = bridge.imgmsg_to_cv2(msg, "bgr8")
elif msg.encoding.find("bggr8")!=-1 :
pix_fmt = "bayer_bggr8"
if self.opt_display_images:
cv_image = bridge.imgmsg_to_cv2(msg, "bayer_bggr8")
elif msg.encoding.find("rggb8")!=-1 :
pix_fmt = "bayer_rggb8"
if self.opt_display_images:
cv_image = bridge.imgmsg_to_cv2(msg, "bayer_rggb8")
elif msg.encoding.find("rgb8")!=-1 :
pix_fmt = "rgb24"
if self.opt_display_images:
cv_image = bridge.imgmsg_to_cv2(msg, "bgr8")
elif msg.encoding.find("16UC1")!=-1 :
pix_fmt = "gray16le"
else:
print('unsupported encoding:', msg.encoding, topic)
#exit(1)
if pix_fmt:
self.write_output_video( msg, topic, t, RAWIMAGE_VIDEO, pix_fmt )
except AttributeError:
# maybe theora packet
# theora not supported
if self.opt_verbose :
print(
一.概念
为什么会存在ROSbag这个东西?ROSbag的作用是什么?
- rosbag作为ros提供的一种工具,它可以记录系统中有关主题的发布的数据。
- 在某些复杂的场景下,我们机器人会偶然触发bug,但是如果要等待复现这种bug可能会花费大量时间,所以可以通过rosbag来复现场景。
所以可以约等于将ROSbag理解为系统日志、机器人运行记录、强队demo。我们可以通过它查看机器人的运行时的信息,或者让机器人通过回放rosbag,以“相同的方式”再运行一次。
二.记录
rosbag
会记录在控制台
的当前目录下。
rosbag record -a
可以记录所有话题的内容rosbag record /topic_name1 /topic_name2 /topic_name3
仅记录有关话题。
rosbag
会默认创建ros的名称,形如Recording to '2021-05-23-16-24-12.bag'
当然可以通过添加-O(-o) finename.bag
的方式添加保存为bag
文件的名字,大小写会导致不同的保存方式:
- eg:
rosbag record -a -O test.bag
[ INFO] [1621758569.611777414]: Recording to 'test.bag'.
rosbag record -o test.bag -a
[ INFO] [1621758533.168720632]: Recording to 'test_2021-05-23-16-28-53.bag'.
三.信息
可以通过info
命令,去显示该rosbag
的信息。
- 方式一,简单查看
rosbag info test.bag
path: test.bag
version: 2.0
duration: 4.8s
start: May 23 2021 16:29:29.62 (1621758569.62)
end: May 23 2021 16:29:34.45 (1621758574.45)
size: 15.8 KB
messages: 18
compression: none [1/1 chunks]
types: rosgraph_msgs/Log [acffd30cd6b6de30f120938c17c593fb]
top/name [7eae61f42fe10628000d2b10fec2f3bd]
topics: /Name_Info 4 msgs : top/name
/rosout 9 msgs : rosgraph_msgs/Log (2 connections)
/rosout_agg 5 msgs : rosgraph_msgs/Log
- 方式二,树状查看,添加参数
-y
kanna@cuit:~$ rosbag info test.bag -y
path: test.bag
version: 2.0
duration: 4.835510
start: 1621758569.616934
end: 1621758574.452444
size: 16204
messages: 18
indexed: True
compression: none
types:
- type: rosgraph_msgs/Log
md5: acffd30cd6b6de30f120938c17c593fb
- type: top/name
md5: 7eae61f42fe10628000d2b10fec2f3bd
topics:
- topic: /Name_Info
type: top/name
messages: 4
- topic: /rosout
type: rosgraph_msgs/Log
messages: 9
connections: 2
- topic: /rosout_agg
type: rosgraph_msgs/Log
messages: 5
三.回放
回放的基础命令:rosbag play file.bag
,空格键可暂停/继续回放。
更改发布速度:rosbag play -r <times> file.bag
,附加参数-r <times>
可以修改播放的速度,比如-r 2
则是二倍速
回放指定话题:rosbag play file.bag --topic /topic1
,即可播放指定话题。