00001
00002
00003 '''
00004 Simple Script to Processes Bag files from RawSnapshot in Release 2.0
00005 and writes the data to file for calibration
00006
00007 Please direct any question to multisense@carnegierobotics.com or
00008 http://support.carnegierobotics.com
00009 '''
00010
00011 import sys
00012 import csv
00013 import time
00014 import os
00015 import numpy as np
00016 import string
00017 try:
00018 import rospy
00019 import rosbag
00020 except:
00021 raise Exception("Error importing ROS. Source the ROS environment" \
00022 +" in the workspace where the multisense stack is located")
00023
00024 class _BagProcessor():
00025
00026 def __init__(self, bag_file):
00027 self.bag_file = bag_file
00028
00029
00030
00031 def process(self, directory='.', rename_file = True,
00032 namespace = 'multisense'):
00033 self.process_laser(directory, namespace)
00034 self.process_image(directory, namespace)
00035 self.process_camera_yaml(directory, namespace)
00036 self.process_laser_yaml(directory, namespace)
00037
00038 return_value = self.bag_file
00039 if rename_file:
00040 return_value = self.rename_bag(directory)
00041
00042 return return_value
00043
00044
00045 def process_laser(self, directory='.', namespace='multisense'):
00046 bag = rosbag.Bag(self.bag_file)
00047 with open(directory + '/' + 'lidarData.csv', 'wb') as laser_file:
00048 topic_name = '/%s/calibration/raw_lidar_data' % namespace
00049 laser_writer = csv.writer(laser_file, delimiter=',')
00050 for topic, msg, t in bag.read_messages(topics=[topic_name]):
00051
00052 scan_count = msg.scan_count
00053 time_start = float(msg.time_start.secs +
00054 msg.time_start.nsecs * 1e-9)
00055 time_end = float(msg.time_end.secs + msg.time_end.nsecs * 1e-9)
00056 angle_start = msg.angle_start
00057 angle_end = msg.angle_end
00058 dist = msg.distance
00059 reflect = msg.intensity
00060
00061
00062
00063 row = [scan_count, time_start, time_end,
00064 angle_start, angle_end, " "] + list(dist) + [" "] \
00065 + list(reflect) + [" "] + [len(list(dist))]
00066
00067 laser_writer.writerow(row)
00068
00069 laser_file.close()
00070
00071
00072
00073
00074 def process_image(self, directory='.', namespace='multisense'):
00075 topic_name = '/%s/calibration/raw_cam_data' % namespace
00076 bag = rosbag.Bag(self.bag_file)
00077
00078
00079 found_rectified_image = False
00080 found_disparity_image = False
00081
00082 for topic, msg, t in bag.read_messages(topics=[topic_name]):
00083 width = msg.width
00084 height = msg.height
00085
00086
00087 if not found_rectified_image and len(list(msg.gray_scale_image)) != 0:
00088 self.write_pgm(np.array(list(msg.gray_scale_image)),
00089 directory + '/' + "stereo_left_0000.pgm",
00090 width, height, 8)
00091 found_rectified_image = True
00092
00093 if not found_disparity_image and len(list(msg.disparity_image)) != 0:
00094 self.write_pgm(np.array(list(msg.disparity_image),
00095 dtype=np.uint16),
00096 directory + '/' + "disparity_0000.pgm",
00097 width, height, 16)
00098 found_disparity_image = True
00099
00100
00101 if found_disparity_image and found_rectified_image:
00102 break
00103
00104
00105 def write_pgm(self, data, name, width, height, bits):
00106 image = open(name, 'wb')
00107
00108
00109 pgm_header = 'P5' + '\n' + str(width) + ' ' \
00110 + str(height) + '\n' + str(2**bits - 1) + '\n'
00111
00112
00113 if bits == 16:
00114 data = data.byteswap()
00115
00116 image.write(pgm_header)
00117 data.tofile(image)
00118 image.close()
00119
00120
00121 def process_camera_yaml(self, directory='.', namespace='multisense'):
00122 topic_name = '/%s/calibration/raw_cam_config' % namespace
00123 bag = rosbag.Bag(self.bag_file)
00124 for topic, msg, t in bag.read_messages(topics=[topic_name]):
00125 fx = msg.fx
00126 fy = msg.fy
00127 cx = msg.cx
00128 cy = msg.cy
00129 tx = msg.tx
00130
00131
00132 p1 = "[ %.17e, 0., %d, 0., 0., \n" % (fx, cx) \
00133 + " %.17e, %d, 0., 0., 0., 1., 0.]" % (fy, cy) \
00134
00135 p2 = "[ %.17e, 0., %d, %.17e, 0., \n" % (fx, cx, tx*fx) \
00136 + " %.17e, %d, 0., 0., 0., 1., 0.]" % (fy, cy) \
00137
00138 self.write_camera_yaml(directory + "/extrinsics_0p5mp.yml", p1, p2)
00139
00140
00141
00142
00143 def write_camera_yaml(self, name, p1, p2):
00144 yaml = open(name, 'wb')
00145
00146 yaml_header = "%YAML:1.0\n"
00147 yaml.write(yaml_header)
00148
00149 p1_header = "P1: !!opencv-matrix\n" \
00150 + " rows: 3\n" \
00151 + " cols: 4\n" \
00152 + " dt: d\n"
00153
00154
00155 p2_header = "P2: !!opencv-matrix\n" \
00156 + " rows: 3\n" \
00157 + " cols: 4\n" \
00158 + " dt: d\n"
00159
00160 yaml.write(p1_header)
00161 yaml.write(" data: " + p1 + '\n\n')
00162 yaml.write(p2_header)
00163 yaml.write(" data: " + p2 + '\n')
00164 yaml.close()
00165
00166
00167
00168 def process_laser_yaml(self, directory=".", namespace='multisense'):
00169 topic_name = '/%s/calibration/raw_lidar_cal' % namespace
00170 bag = rosbag.Bag(self.bag_file)
00171 i = 0
00172 for topic, msg, t in bag.read_messages(topics=[topic_name]):
00173
00174
00175 if i > 0:
00176 break
00177
00178 lts = list(msg.laserToSpindle)
00179
00180 cts = list(msg.cameraToSpindleFixed)
00181
00182
00183 laser_t_spind = "[ %.17e, %.17e,\n" % (lts[0], lts[1]) \
00184 +" %.17e, %.17e,\n" % (lts[2], lts[3]) \
00185 +" %.17e, %.17e,\n" % (lts[4], lts[5]) \
00186 +" %.17e, %.17e,\n" % (lts[6], lts[7]) \
00187 +" %.17e, %.17e,\n" % (lts[8], lts[9]) \
00188 +" %.17e, 0., 0., 0., 0., 1. ]" % (lts[10])
00189
00190
00191 camera_t_spind = "[ %.17e, %.17e,\n" % (cts[0], cts[1]) \
00192 +" %.17e, %.17e,\n" % (cts[2], cts[3]) \
00193 +" %.17e, %.17e,\n" % (cts[4], cts[5]) \
00194 +" %.17e, %.17e,\n" % (cts[6], cts[7]) \
00195 +" %.17e, %.17e,\n" % (cts[8], cts[9]) \
00196 +" %.17e, %.17e, 0., 0., 0., 1. ]" % (cts[10], cts[11])
00197
00198 self.write_laser_yaml(directory + "/laser_cal.yml",
00199 laser_t_spind, camera_t_spind)
00200 i = i+1
00201
00202
00203 def write_laser_yaml(self, name, laser_t_spind, cam_t_spind):
00204 yaml = open(name, 'wb')
00205 yaml_header = "%YAML:1.0\n"
00206 yaml.write(yaml_header)
00207
00208 laser_t_spind_h = "laser_T_spindle: !!opencv-matrix\n" \
00209 +" rows: 4\n" \
00210 +" cols: 4\n" \
00211 +" dt: d\n"
00212
00213 cam_t_spind_h = "camera_T_spindle_fixed: !!opencv-matrix\n" \
00214 +" rows: 4\n" \
00215 +" cols: 4\n" \
00216 +" dt: d\n"
00217
00218 yaml.write(laser_t_spind_h)
00219 yaml.write(" data: " + laser_t_spind + '\n')
00220 yaml.write(cam_t_spind_h)
00221 yaml.write(" data: " + cam_t_spind + '\n')
00222 yaml.close()
00223
00224
00225
00226 def rename_bag(self, directory=".", namespace='multisense'):
00227 topic_name = '/%s/calibration/device_info' % namespace
00228 bag = rosbag.Bag(self.bag_file)
00229 for topic, msg, t in bag.read_messages(topics=[topic_name]):
00230
00231
00232
00233 sn = msg.serialNumber.strip()
00234 exclude_characters = string.letters + string.punctuation + " "
00235 sn = sn.strip(exclude_characters)
00236
00237
00238
00239 try:
00240 sn = "SN%04d" % int(sn)
00241 except:
00242 sn = "SN" + sn
00243
00244 info = open(os.path.join(directory, "dev_info.txt"), 'wb')
00245
00246 info.write(str(msg))
00247 info.close
00248
00249
00250 bag = os.path.basename(self.bag_file)
00251 path = os.path.dirname(self.bag_file)
00252
00253 fname = os.path.join(path, os.path.splitext(bag)[0]\
00254 + "_SL_%s_calCheck.bag" % sn)
00255
00256
00257 os.rename(self.bag_file, fname)
00258 self.bag_file = fname
00259 return fname
00260
00261
00262 def usage(argv):
00263 print "\nUsage: %s bagFile <outputDirectory> <namespace>" % argv[0]
00264 print ""
00265 print "If no value is specified for outputDirectory, then a "
00266 print "directory will be created using the current time as "
00267 print "part of its name."
00268 print ""
00269 print "If a value is provided for namespace, it will be used "
00270 print "in extracting data from the bag file. The default namespace "
00271 print "is multisense. You might want to specify multisense_sl or "
00272 print "laser instead, if you are processing an older bag file."
00273
00274
00275 if __name__ == '__main__':
00276
00277 bag_file_name = 'dummy.bag'
00278 output_directory_name = time.strftime('%Y-%m-%d_%H-%M-%S_process_bags')
00279 namespace = 'multisense'
00280 rename_file = True
00281
00282
00283 if (len(sys.argv) < 2) | (len(sys.argv) > 4):
00284 usage(sys.argv)
00285 sys.exit(65)
00286
00287 if len(sys.argv) >= 2:
00288 bag_file_name = sys.argv[1]
00289
00290 if len(sys.argv) >= 3:
00291 output_directory_name = sys.argv[2]
00292
00293 if len(sys.argv) >= 4:
00294 namespace = sys.argv[3]
00295
00296
00297
00298 if not os.path.exists(output_directory_name):
00299 os.makedirs(output_directory_name)
00300
00301 if not os.path.isdir(output_directory_name):
00302 raise IOError('%s is not a directory' % output_directory_name)
00303
00304
00305
00306 bagProcessor = _BagProcessor(bag_file_name)
00307 bagProcessor.process(output_directory_name, rename_file, namespace)
00308 sys.exit(0)
00309