Skip to content

Commit

Permalink
Merge pull request #1738 from iory/rosbag-tools
Browse files Browse the repository at this point in the history
Add jsk_rosbag_tools package
  • Loading branch information
k-okada authored Jul 3, 2022
2 parents 6881483 + 007febb commit 7147133
Show file tree
Hide file tree
Showing 31 changed files with 1,812 additions and 0 deletions.
1 change: 1 addition & 0 deletions jsk_common/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<exec_depend>audio_video_recorder</exec_depend>
<exec_depend>dynamic_tf_publisher</exec_depend>
<exec_depend>image_view2</exec_depend>
<exec_depend>jsk_rosbag_tools</exec_depend>
<exec_depend>jsk_topic_tools</exec_depend>
<exec_depend>jsk_tools</exec_depend>
<exec_depend>multi_map_server</exec_depend>
Expand Down
2 changes: 2 additions & 0 deletions jsk_rosbag_tools/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
!.gitignore
requirements.txt
83 changes: 83 additions & 0 deletions jsk_rosbag_tools/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
cmake_minimum_required(VERSION 2.8.3)
project(jsk_rosbag_tools)

find_package(
catkin REQUIRED
catkin_virtualenv
)

if (${catkin_virtualenv_VERSION} VERSION_LESS "0.5.1")
message(STATUS "jsk_rosbag_tools requires catkin_virtualenv >= 0.5.1")
return()
endif()


catkin_python_setup()

catkin_package(
CATKIN_DEPENDS
)

if($ENV{ROS_DISTRO} STREQUAL "noetic")
catkin_generate_virtualenv(
INPUT_REQUIREMENTS requirements.in
PYTHON_INTERPRETER python3
)
else()
catkin_generate_virtualenv(
INPUT_REQUIREMENTS requirements.in
)
endif()

file(GLOB SCRIPTS_FILES scripts/*)
catkin_install_python(
PROGRAMS ${SCRIPTS_FILES}
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

catkin_download(download_audio_data
https://drive.google.com/uc?export=download&id=1rFZYoFjLqIWjEe0DaNiL3k9893m31nu7
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/samples/data
FILENAME 2022-05-07-hello-test.bag
MD5 3650e27dad2c7dc0e447033259290db6
)
catkin_download(download_video_data
https://drive.google.com/uc?export=download&id=1v4YNOHnHYxLOty1lYR2R6lfNF0itCwK7
DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/samples/data
FILENAME 20220530173950_go_to_kitchen_rosbag.bag
MD5 d51fa8aeacd36f7aaa1597b67bd9ffdf
)
add_custom_target(download ALL DEPENDS download_audio_data download_video_data)

if(CATKIN_ENABLE_TESTING)
find_package(catkin REQUIRED COMPONENTS roslint rostest)

set(python_test_scripts
tests/test_jsk_rosbag_tools.py
tests/test_bag_to_video.py
)

roslint_python()
roslint_python(${python_test_scripts})
roslint_add_test()

catkin_install_python(PROGRAMS ${python_test_scripts}
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

add_rostest(tests/test_jsk_rosbag_tools.test
DEPENDENCIES ${PROJECT_NAME}_generate_virtualenv download_audio_data download_video_data)
if("$ENV{ROS_DISTRO}" STRGREATER "indigo")
# could not install moviepy on indigo.
add_rostest(tests/test_bag_to_video.test
DEPENDENCIES ${PROJECT_NAME}_generate_virtualenv download_audio_data download_video_data)
endif()
endif()

install(DIRECTORY scripts samples
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
USE_SOURCE_PERMISSIONS
)

install(FILES requirements.txt
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)
195 changes: 195 additions & 0 deletions jsk_rosbag_tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# jsk_rosbag_tools

Tools such as creating video from rosbag and compressing rosbag images.

## bag_to_video.py

Create video from rosbag.

### Usage

```
usage: bag_to_video.py [-h] [--out OUT] [--fps FPS] [--samplerate SAMPLERATE] [--channels CHANNELS] [--audio-topic AUDIO_TOPIC] [--image-topic IMAGE_TOPIC [IMAGE_TOPIC ...]] input_bagfile
rosbag to video
positional arguments:
input_bagfile
optional arguments:
-h, --help show this help message and exit
--out OUT, -o OUT output directory path or filename.
If more than one --image-topic are specified,
this will be interpreted as a directory name.
Otherwise this is the file name.
--fps FPS
--samplerate SAMPLERATE, -r SAMPLERATE
sampling rate
--channels CHANNELS number of input channels
--audio-topic AUDIO_TOPIC
--image-topic IMAGE_TOPIC [IMAGE_TOPIC ...]
Topic name to extract.
```

### Example

```
rosrun jsk_rosbag_tools bag_to_video.py $(rospack find jsk_rosbag_tools)/samples/data/20220530173950_go_to_kitchen_rosbag.bag \
--samplerate 16000 --channels 1 --audio-topic /audio \
--image-topic /head_camera/rgb/throttled/image_rect_color/compressed \
-o /tmp/20220530173950_go_to_kitchen_rosbag.mp4
```

## bag_to_audio.py

Create audio file from rosbag.

### Usage

```
usage: bag_to_audio.py [-h] [--out OUT] [--samplerate SAMPLERATE] [--channels CHANNELS] [--audio-topic AUDIO_TOPIC] input_bagfile
rosbag to audio
positional arguments:
input_bagfile
optional arguments:
-h, --help show this help message and exit
--out OUT, -o OUT output filename. If `--audio-topic`_info is exists, you don't have to specify samplerate and channels.
--samplerate SAMPLERATE, -r SAMPLERATE
sampling rate
--channels CHANNELS number of input channels
--audio-topic AUDIO_TOPIC
```

### Example

```
rosrun jsk_rosbag_tools bag_to_audio.py $(rospack find jsk_rosbag_tools)/samples/data/20220530173950_go_to_kitchen_rosbag.bag \
--samplerate 16000 --channels 1 --audio-topic /audio \
-o /tmp/20220530173950_go_to_kitchen_rosbag.wav
```

## video_to_bag.py

Convert video file to bagfile.

### Usage

```
usage: video_to_bag.py [-h] [--out output_file] [--topic-name TOPIC_NAME] [--compress] [--no-progress-bar] inputvideo
Convert video to bag.
positional arguments:
inputvideo
optional arguments:
-h, --help show this help message and exit
--out output_file, -o output_file
name of the output bag file
--topic-name TOPIC_NAME
Converted topic name.
--compress Compress Image flag.
--no-progress-bar Don't show progress bar.
```

### Example

```
rosrun jsk_rosbag_tools video_to_bag.py /tmp/output_bag/head_camera--slash--rgb--slash--throttled--slash--image_rect_color--slash--compressed-with-audio.mp4 \
-o /tmp/output_bag/video.bag --compress
```

## compress_imgs.py

Convert `Image` messages to `CompressedImage` or `CompressedDepthImage`.

### Usage

```
usage: compress_imgs.py [-h] [--out OUT] [--compressed-topics [COMPRESSED_TOPICS [COMPRESSED_TOPICS ...]]] [--replace] [--no-progress-bar] input_bagfile
Convert Image messages to CompressedImage or CompressedDepthImage
positional arguments:
input_bagfile input bagfile path
optional arguments:
-h, --help show this help message and exit
--out OUT, -o OUT output bagfile path
--compressed-topics [COMPRESSED_TOPICS [COMPRESSED_TOPICS ...]]
this image topics are compressed
--replace
--no-progress-bar Don't show progress bar.
```

### Example

```
rosrun jsk_rosbag_tools compress_imgs.py $(rospack find jsk_rosbag_tools)/samples/data/20220530173950_go_to_kitchen_rosbag.bag \
-o /tmp/20220530173950_go_to_kitchen_rosbag-compressed.bag
```

## tf_static_to_tf.py

Convert tf_static to tf and save it as a rosbag.

```
usage: tf_static_to_tf.py [-h] [--out OUT] [--no-progress-bar] input_bagfile
Convert tf_static to tf and save it as a rosbag
positional arguments:
input_bagfile input bagfile path
optional arguments:
-h, --help show this help message and exit
--out OUT, -o OUT output bagfile path
--no-progress-bar Don't show progress bar.
```

### Example

```
rosrun jsk_rosbag_tools tf_static_to_tf.py $(rospack find jsk_rosbag_tools)/samples/data/20220530173950_go_to_kitchen_rosbag.bag
```

### Note

`jsk_topic_tools` has a [static_tf_republisher.py](https://jsk-docs.readthedocs.io/projects/jsk_common/en/latest/jsk_topic_tools/scripts/static_tf_republisher.html) which republish `/tf_static` from a rosbag file.

`tf_static_to_tf.py` is an approach to rewrite the rosbag file.

## merge.py

Merges two bagfiles.

### Usage

```
usage: merge.py [-h] [--out output_file] [--topics TOPICS] [-i] main_bagfile bagfile
Merges two bagfiles.
positional arguments:
main_bagfile path to a bagfile, which will be the main bagfile
bagfile path to a bagfile which should be merged to the main bagfile
optional arguments:
-h, --help show this help message and exit
--out output_file, -o output_file
name of the output file
--topics TOPICS, -t TOPICS
topics which should be merged to the main bag
-i reindex bagfile
```

### Example

```
rosrun jsk_rosbag_tools merge.py \
$(rospack find jsk_rosbag_tools)/samples/data/20220530173950_go_to_kitchen_rosbag.bag \
$(rospack find jsk_rosbag_tools)/samples/data/2022-05-07-hello-test.bag
```
42 changes: 42 additions & 0 deletions jsk_rosbag_tools/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0"?>
<package format="3">
<name>jsk_rosbag_tools</name>
<version>2.2.11</version>
<description>The rosbag tools</description>
<license>BSD</license>

<maintainer email="[email protected]">Iori Yanokura</maintainer>
<author email="[email protected]">Iori Yanokura</author>

<buildtool_depend>catkin</buildtool_depend>
<buildtool_depend>python-catkin-pkg-modules</buildtool_depend>

<build_depend version_gte="0.5.1">catkin_virtualenv</build_depend>

<exec_depend>audio_common_msgs</exec_depend>
<exec_depend>cv_bridge</exec_depend>
<exec_depend>ffmpeg</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-numpy</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-rospkg-modules</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-scipy</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-setuptools</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-termcolor</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-tqdm</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-yaml</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-numpy</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-rospkg-modules</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-scipy</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-setuptools</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-termcolor</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-tqdm</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-yaml</exec_depend>
<exec_depend>sensor_msgs</exec_depend>

<test_depend>roslint</test_depend>
<test_depend>rostest</test_depend>

<export>
<pip_requirements>requirements.txt</pip_requirements>
</export>

</package>
1 change: 1 addition & 0 deletions jsk_rosbag_tools/python/jsk_rosbag_tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# flake8: noqa
50 changes: 50 additions & 0 deletions jsk_rosbag_tools/python/jsk_rosbag_tools/bag_to_audio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import os
import os.path as osp

import numpy as np
import rosbag
from scipy.io.wavfile import write as wav_write

from jsk_rosbag_tools.extract import extract_oneshot_topic
from jsk_rosbag_tools.info import get_topic_dict
from jsk_rosbag_tools.makedirs import makedirs


def bag_to_audio(bag_filepath,
wav_outpath,
topic_name='/audio',
audio_info_topic_name=None,
samplerate=44100,
channels=1,
overwrite=True):
if os.path.exists(wav_outpath) and overwrite is False:
raise FileExistsError('{} file already exists.'.format(wav_outpath))
topic_dict = get_topic_dict(bag_filepath)
if topic_name not in topic_dict:
return

audio_info_topic_name = audio_info_topic_name or topic_name + '_info'
# if audio_info_topic exists, extract info from it.
if audio_info_topic_name in topic_dict:
audio_info = extract_oneshot_topic(bag_filepath, audio_info_topic_name)
if audio_info is not None:
samplerate = audio_info.sample_rate
channels = audio_info.channels

bag = rosbag.Bag(bag_filepath)
audio_buffer = []
for _, msg, _ in bag.read_messages(topics=[topic_name]):
if msg._type == 'audio_common_msgs/AudioData':
buf = np.frombuffer(msg.data, dtype='int16')
buf = buf.reshape(-1, channels)
audio_buffer.append(buf)
audio_buffer = np.concatenate(audio_buffer, axis=0)

makedirs(osp.dirname(wav_outpath))
wav_write(wav_outpath, rate=samplerate, data=audio_buffer)

valid = os.stat(wav_outpath).st_size != 0
if valid is False:
return False

return True
Loading

0 comments on commit 7147133

Please sign in to comment.