ROS系列(二):rosbag 中提取视频数据

news2024/11/27 4:19:19

一、环境安装

当前环境在上一篇文章的基础上进行配置。

ROS系列(一):【环境配置】rosbag 包安装_安装rosbag-CSDN博客

继续安装

sudo apt install ffmpeg

python 包如下

pip install sensor_msgs --extra-index-url https://rospypi.github.io/simple/
pip install geometry_msgs --extra-index-url https://rospypi.github.io/simple/
pip install opencv-python

安装好环境后:

使用如下脚本:

#!/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("Could not handle this format. Maybe thoera packet? theora is not supported.")
                    pass
            if self.opt_display_images:
                cv2.imshow(topic, cv_image)
                key=cv2.waitKey(1)
                if key==1048603:
                    exit(1)
        if self.p_avconv == {}:
            print("No image topics found in bag:", filename)
        bag.close()



if __name__ == '__main__':
    #print()
    #print('rosbag2video, by Maximilian Laiacker 2020 and Abel Gabor 2019')
    #print()

    if len(sys.argv) < 2:
        print('Please specify ros bag file(s)!')
        print_help()
        sys.exit(1)
    else :
        videowriter = RosVideoWriter()
        try:
            opt_files = videowriter.parseArgs(sys.argv[1:])
        except getopt.GetoptError:
            print_help()
            sys.exit(2)


    # loop over all files
    for files in range(0,len(opt_files)):
        #First arg is the bag to look at
        bagfile = opt_files[files]
        videowriter.addBag(bagfile)
    print("finished")
使用方法介绍:

python rosbag2video.py XXX.bag

参数说明:

[–fps] :设置传递给ffmpeg的帧率,默认为25;
[-h]:显示帮助;
[–ofile]:设置输出文件名;
[–rate]:放慢或加快视频。默认值是1.0,保持原来的速度;
[-s]:显示从rosbag文件提取的每个图像;
[–topic]:仅来自“topic”的图像用于视频输出;
[-v]:显示详细消息;
[–prefix]:设置输出文件名前缀,否则使用“ bagfile1”(如果未设置-o);
[–start]:可选的开始时间(以秒为单位);
[–end]:可选结束时间,单位为秒;

执行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1097002.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ASP.NET LIMS系统全套源码(演示+自主版权+项目使用)

基于ASP.NET Dotnet 3.5 EXT.NETMSSQL 2018技术架构开发的LIMS系统全套源码&#xff08;演示自主版权项目使用&#xff09; LIMS是为检测组织全流程业务设计的。以实验室为中心&#xff0c;将实验室的业务流程、环境、人员、仪器设备、标物标液、化学试剂、规范办法、图书资料、…

[C++]:1.初识C++和C语言缺陷补充。

初识C和C语言缺陷补充 一.主要内容&#xff1a;二.具体内容&#xff1a;一&#xff1a; 作用域1.命名空间&#xff1a;2.函数声明和定义&#xff1a;3.不存在命名冲突的情况&#xff1a; 二.输入输出&#xff1a;1.基本输入输出&#xff1a;2.关于std的展开&#xff1a; 三.函数…

Docker逃逸---SYS_PTRACE浅析

一、产生原因 用户授予了容器SYS_PTRACE权限&#xff0c;并且与宿主机共享一个进程命名空间(--pidhost)&#xff0c;使得容器内可以查看到宿主机的进程&#xff0c;攻击者可以利用进程注入&#xff0c;反弹shell&#xff0c;从而实现逃逸 二、利用条件 1、容器有SYS_PTRACE权…

解决安装nvm以后windows cmd无法找到npm/yarn命令的问题

安装了nodejs多版本管理工具nvm以后&#xff0c;会出现windows cmd无法找到npm/yarn命令的问题 只要一运行npm/yarn就会提示&#xff1a;不是内部命令&#xff0c;找不到运行路径之类的。 解决办法&#xff1a;首先打开windows环境变量的配置&#xff0c;查看NVM_SYMLINK指向…

55 零钱兑换

零钱兑换 题解1 DP另一种解法(更好记) 题解2 递归 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额&#xff0c;返回…

点赞“美丽南苑人”㉒ | 施晨阳:以青春之名 赴亚运之约

为积极培育和践行社会主义核心价值观&#xff0c;引导和激励辖区群众学习身边先进典型的道德品质和价值追求&#xff0c;进一步发挥“美丽人物”的典型示范和带动引领作用&#xff0c;南苑街道开启“点赞‘美丽南苑人’”专栏&#xff0c;向大家讲述“美丽南苑人”的故事&#…

选择共享wifi项目哪个公司好?!

当今社会&#xff0c;无线网络成为了人们生活中必不可少的一部分。在日常生活中&#xff0c;我们可能会遇到寻找WiFi的情况&#xff0c;共享WiFi逐渐成为人们越来越常用的网络连接方式&#xff0c;随着共享WiFi服务商的不断增多&#xff0c;创业者如何如何挑选和判断哪家共享Wi…

金融考研人通向成功的快速通道——中国人民大学与加拿大女王大学金融硕士

在金融行业中&#xff0c;有这样一个中外合作办学硕士&#xff0c;它成为了很多金融考研人通向成功的快速通道。它免全国联考&#xff0c;学制一年&#xff0c;无英语要求&#xff0c;看到这里&#xff0c;王老师壹柒叁壹陆壹久领悟刘玲&#xff0c;很多同学是不是已经猜到了&a…

PNG转EPS,包括Latex导入

在电脑TEXLIVE文件夹里中找到bmeps.exe TEXLIVE\2022\bin\win32 可以新建一个文件夹picture&#xff08;图片和exe文件必须在一个文件夹里&#xff09;&#xff0c;将bmeps.exe复制出来&#xff0c;方便后续大量图片操作 导入png图片 新建一个txt文件&#xff0c;命名为Fig1.…

php74 安装sodium

下载编译安装libsodium wget https://download.libsodium.org/libsodium/releases/libsodium-1.0.18-stable.tar.gz tar -zxf libsodium-1.0.18-stable.tar.gz cd libsodium-stable ./configure --without-libsodium make && make check sudo make install下载编译安装…

【Redis】高效保障MySQL和Redis的数据一致性?

高效保障MySQL和Redis的数据一致性? 在满足实时性的条件下,不存在两者完全保存一致的方案,只有最终一致性方案。根据网上的众多解决方案,总结出 6 种,直接看目录: 不好的方案 1、先写 MySQL,再写 Redis 如图所示: 这是一副时序图,描述请求的先后调用顺序; 橘黄…

Macos数据库管理:Navicat Premium 中文

Navicat Premium提供了直观且易用的图形用户界面&#xff0c;使得操作更为便捷。Navicat Premium 中文支持多种数据库系统&#xff0c;如MySQL、MariaDB、Oracle、SQLite、PostgreSQL等&#xff0c;可以让用户在同一平台上管理不同类型的数据库。Navicat Premium拥有强大的数据…

BUUCTF学习(四): 文件包含tips

1、介绍 2、hackBar插件安装 教程&#xff1a; Hackbar插件安装-CSDN博客 3、解题 php://filter/readconvert.base64-encode/resource要读取的文件 ?filephp://filter/readconvert.base64-encode/resourceflag.php Base64 在线编码解码 | Base64 加密解密 - Base64.us 结束

剑指offer(C++)-JZ50:第一个只出现一次的字符(算法-其他)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 在一个长为 字符串中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1&#xff08;需要区分…

传统鞋业焕发智造魅力,健康鞋步力宝品牌数字化转型助力多方把控

随着经济环境的变化以及市场竞争的加剧&#xff0c;加之我国劳动力、土地以及资源环境成本的快速上升&#xff0c;以劳动密集型为主、通过低附加值方式发展的传统产业集群遭遇瓶颈。而数字化时代的到来&#xff0c;不仅给各行各业带来了巨大的变革&#xff0c;也为传统鞋服业带…

王兴投资5G小基站

边缘计算社区获悉&#xff0c;近期深圳佳贤通信正式完成数亿元股权融资&#xff0c;本轮融资由美团龙珠领投。本轮融资资金主要用于技术研发、市场拓展等&#xff0c;将进一步巩固和扩大佳贤通信在5G小基站领域的技术及市场领先地位。 01 佳贤通信是什么样的公司&#xff1f; 深…

BIO实战、NIO编程与直接内存、零拷贝深入剖析

原生 JDK 网络编程 BIO BIO&#xff0c;意为 Blocking I/O&#xff0c;即阻塞的 I/O。   BIO 基本上就是我们上面所说的生活场景的朴素实现。在 BIO 中类 ServerSocket 负责绑定 IP 地址&#xff0c;启动监听端口&#xff0c;等待客户连接&#xff1b;客户端 Socket 类的实例…

倍福TwinCAT3.0软件与C++通讯问题(EAP通讯)

文章目录 一. TwinCAT控制器之间的几种通讯方式1.添加EAP设备2.添加变量刷新的Task周期3. 测试 一. TwinCAT控制器之间的几种通讯方式 协议硬件要求实时性说明ADS通讯普通网卡&#xff0c;支持无线典型值&#xff1a;< 100msServer/Client&#xff0c;要写 PLC 程序&#x…

全志R128芯片应用开发案例——ADC驱动烟雾传感器

ADC驱动烟雾传感器 本文案例代码下载地址ADC驱动烟雾传感器案例代码https://www.aw-ol.com/downloads?cat24 原理介绍 MQ-2型烟雾传感器属于二氧化锡半导体气敏材料&#xff0c;属于表面离子式N型半 导体。当处于200、300℃温度时&#xff0c;二氧化锡吸附空气中的氧&#…

网络端口验证

网络端口连通性验证 1、背景2、目标3、环境4、部署4.1、准备工作4.2、安装4.3、场景测试 1、背景 在日常运维过程中经常会遇到以下两种场景&#xff1a; 1、程序业务端口的开具及验证 2、业务程序访问异常网络排障 2、目标 1、验证端口的正确开具 2、网络策略的连通性 3、环…