rosbag_image_compressor.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Copyright 2014 Open Source Robotics Foundation
00004 #
00005 # Licensed under the Apache License, Version 2.0 (the "License");
00006 # you may not use this file except in compliance with the License.
00007 # You may obtain a copy of the License at
00008 #
00009 #     http://www.apache.org/licenses/LICENSE-2.0
00010 #
00011 # Unless required by applicable law or agreed to in writing, software
00012 # distributed under the License is distributed on an "AS IS" BASIS,
00013 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 # See the License for the specific language governing permissions and
00015 # limitations under the License.
00016 
00017 
00018 from io import BytesIO
00019 import os
00020 from PIL import Image
00021 import rosbag
00022 from sensor_msgs.msg import CompressedImage
00023 from sensor_msgs.msg import Image as smImage
00024 from std_msgs.msg import String
00025 
00026 
00027 def compress_image(msg):
00028     """
00029     Take a sensor_msgs/Image
00030     return a sensor_msgs/CompressedImage
00031     """
00032     # fromstring is not available on precise python-imaging v 1.1.7
00033     # but has been deprecated in v 2.0 using it for now while we need
00034     # to support precise
00035     # img = Image.frombytes("L", (msg.width, msg.height), msg.data,
00036     #                       'raw', "L", 0, 1)
00037     img = Image.fromstring("L", (msg.width, msg.height), msg.data,
00038                            'raw', "L", 0, 1)
00039     # img.show()
00040     output = BytesIO()
00041     img.save(output, format='png')
00042     output.flush()
00043 
00044     output_msg = CompressedImage()
00045     output_msg.header = msg.header
00046     output_msg.format = 'png'
00047     output_msg.data = output.getvalue()
00048 
00049     encoding_msg = String()
00050     encoding_msg.data = msg.encoding
00051     return output_msg, encoding_msg
00052 
00053 
00054 def uncompress_image(compressed_msg, encoding):
00055     """
00056     Take a sensor_msgs/CompressedImage and encoding
00057     This will assume the compression has ignored the encoding and
00058     will apply the encoding
00059     return a sensor_msgs/Image
00060     """
00061     fh = BytesIO(compressed_msg.data)
00062     img = Image.open(fh)
00063 
00064     output_msg = smImage()
00065     output_msg.header = compressed_msg.header
00066     output_msg.width, output_msg.height = img.size
00067     output_msg.encoding = encoding
00068     output_msg.is_bigendian = False  # TODO
00069     output_msg.step = output_msg.width
00070     output_msg.data = img.tostring()
00071     return output_msg
00072 
00073 
00074 def image_topic_basename(topic):
00075     """ A convenience method for stripping the endings off an image topic"""
00076     endings = ['compressed', 'encoding', 'image_raw']
00077     for e in endings:
00078         if topic.endswith(e):
00079             return topic[:-1 * len(e)]
00080     raise Exception("invalid topic for truncation %s looking for endings %s" %
00081                     (topic, endings))
00082 
00083 
00084 class EncodingCache:
00085 
00086     """ A class for caching the encoding type for each topic. This will only
00087     work if the encoding does not change. """
00088 
00089     def __init__(self):
00090         self.encoding_map = {}
00091 
00092     def lookup_encoding(self, topic):
00093         if topic in self.encoding_map:
00094             return self.encoding_map[topic]
00095         else:
00096             raise Exception("failed to find encoding for topic %s in %s" %
00097                             (topic, self.encoding_map))
00098 
00099     def insert_encoding(self, topic, encoding):
00100         self.encoding_map[topic] = encoding
00101 
00102 
00103 def compress(bagfile_in, bagfile_out):
00104     """ Iterate over bagfile_in and compress images into bagfile_out """
00105     with rosbag.Bag(bagfile_in) as bag:
00106         with rosbag.Bag(bagfile_out, 'w') as outbag:
00107             process_log = {}
00108             print("Compressing %s into %s" % (bagfile_in, bagfile_out))
00109             for topic, msg, t in bag.read_messages():
00110                 if topic.endswith('image_raw'):
00111                     # print("compressing %s, time is %s" % (topic, t))
00112                     bname = image_topic_basename(topic)
00113                     try:
00114                         msg, encoding_msg = compress_image(msg)
00115                         encoding_topic = bname + "encoding"
00116                         topic = bname + "compressed"
00117                         outbag.write(encoding_topic, encoding_msg, t)
00118                         if bname in process_log:
00119                             process_log[bname] += 1
00120                         else:
00121                             process_log[bname] = 1
00122                     except Exception as ex:
00123                         print("Exception: %s when parsing msg. Not compressing" % ex)
00124 
00125                 # print("%s" % output_msg)
00126                 outbag.write(topic, msg, t)
00127             if not process_log:
00128                 print("No images compressed")
00129             for t, c in process_log.items():
00130                 print("Compressed %s message on topic %simage_raw" % (c, t))
00131 
00132 
00133 def uncompress(bagfile_in, bagfile_out):
00134     """ Iterate over bagfile_in and decompress images into bagfile_out """
00135     with rosbag.Bag(bagfile_in) as bag:
00136         with rosbag.Bag(bagfile_out, 'w') as outbag:
00137             process_log = {}
00138             print("Decompressing %s into %s" % (bagfile_in, bagfile_out))
00139             encoding_cache = EncodingCache()
00140             for topic, msg, t in bag.read_messages():
00141                 bname = image_topic_basename(topic)
00142                 if topic.endswith('encoding'):
00143                     encoding_cache.insert_encoding(bname, msg.data)
00144                     continue  # do not rewrite the encoding message
00145                 if topic.endswith('compressed'):
00146                     # print("uncompressing %s, time is %s" % (topic, t))
00147                     try:
00148                         enc = encoding_cache.lookup_encoding(bname)
00149                         msg = uncompress_image(msg, enc)
00150                         topic = bname + 'image_raw'
00151                         if bname in process_log:
00152                             process_log[bname] += 1
00153                         else:
00154                             process_log[bname] = 1
00155                     except Exception as ex:
00156                         print("Exception: %s when parsing msg. Not decompressing" % ex)
00157 
00158                 # print("%s" % output_msg)
00159                 outbag.write(topic, msg, t)
00160             if not process_log:
00161                 print("No images decompressed")
00162             for t, c in process_log.items():
00163                 print("Decompressed %s message on topic %scompressed" % (c, t))


rosbag_image_compressor
Author(s):
autogenerated on Thu Aug 27 2015 14:50:43