00001 import sys
00002 import time
00003 import rospy
00004 from sensor_msgs.msg import Image as msg_Image
00005 from sensor_msgs.msg import PointCloud2 as msg_PointCloud2
00006 import sensor_msgs.point_cloud2 as pc2
00007 from sensor_msgs.msg import Imu as msg_Imu
00008 import numpy as np
00009 from cv_bridge import CvBridge, CvBridgeError
00010 import inspect
00011 import ctypes
00012 import struct
00013 import tf
00014
00015
00016 def pc2_to_xyzrgb(point):
00017
00018 x, y, z = point[:3]
00019 rgb = point[3]
00020
00021
00022 s = struct.pack('>f', rgb)
00023 i = struct.unpack('>l', s)[0]
00024
00025 pack = ctypes.c_uint32(i).value
00026 r = (pack & 0x00FF0000) >> 16
00027 g = (pack & 0x0000FF00) >> 8
00028 b = (pack & 0x000000FF)
00029 return x, y, z, r, g, b
00030
00031
00032 class CWaitForMessage:
00033 def __init__(self, params={}):
00034 self.result = None
00035
00036 self.break_timeout = False
00037 self.timeout = params.get('timeout_secs', -1)
00038 self.seq = params.get('seq', -1)
00039 self.time = params.get('time', None)
00040 self.node_name = params.get('node_name', 'rs2_listener')
00041 self.bridge = CvBridge()
00042 self.listener = None
00043
00044 self.themes = {'depthStream': {'topic': '/camera/depth/image_rect_raw', 'callback': self.imageColorCallback, 'msg_type': msg_Image},
00045 'colorStream': {'topic': '/camera/color/image_raw', 'callback': self.imageColorCallback, 'msg_type': msg_Image},
00046 'pointscloud': {'topic': '/camera/depth/color/points', 'callback': self.pointscloudCallback, 'msg_type': msg_PointCloud2},
00047 'alignedDepthInfra1': {'topic': '/camera/aligned_depth_to_infra1/image_raw', 'callback': self.imageColorCallback, 'msg_type': msg_Image},
00048 'alignedDepthColor': {'topic': '/camera/aligned_depth_to_color/image_raw', 'callback': self.imageColorCallback, 'msg_type': msg_Image},
00049 'static_tf': {'topic': '/camera/color/image_raw', 'callback': self.imageColorCallback, 'msg_type': msg_Image},
00050 'accelStream': {'topic': '/camera/accel/sample', 'callback': self.imuCallback, 'msg_type': msg_Imu},
00051 }
00052
00053 self.func_data = dict()
00054
00055 def imuCallback(self, theme_name):
00056 def _imuCallback(data):
00057 if self.listener is None:
00058 self.listener = tf.TransformListener()
00059 self.prev_time = time.time()
00060 self.func_data[theme_name].setdefault('value', [])
00061 self.func_data[theme_name].setdefault('ros_value', [])
00062 try:
00063 frame_id = data.header.frame_id
00064 value = data.linear_acceleration
00065
00066 (trans,rot) = self.listener.lookupTransform('/camera_link', frame_id, rospy.Time(0))
00067 quat = tf.transformations.quaternion_matrix(rot)
00068 point = np.matrix([value.x, value.y, value.z, 1], dtype='float32')
00069 point.resize((4, 1))
00070 rotated = quat*point
00071 rotated.resize(1,4)
00072 rotated = np.array(rotated)[0][:3]
00073 except Exception as e:
00074 print(e)
00075 return
00076 self.func_data[theme_name]['value'].append(value)
00077 self.func_data[theme_name]['ros_value'].append(rotated)
00078 return _imuCallback
00079
00080 def imageColorCallback(self, theme_name):
00081 def _imageColorCallback(data):
00082 self.prev_time = time.time()
00083 self.func_data[theme_name].setdefault('avg', [])
00084 self.func_data[theme_name].setdefault('ok_percent', [])
00085 self.func_data[theme_name].setdefault('num_channels', [])
00086 self.func_data[theme_name].setdefault('shape', [])
00087 self.func_data[theme_name].setdefault('reported_size', [])
00088
00089 try:
00090 cv_image = self.bridge.imgmsg_to_cv2(data, data.encoding)
00091 except CvBridgeError as e:
00092 print(e)
00093 return
00094 channels = cv_image.shape[2] if len(cv_image.shape) > 2 else 1
00095 pyimg = np.asarray(cv_image)
00096
00097 ok_number = (pyimg != 0).sum()
00098
00099 self.func_data[theme_name]['avg'].append(pyimg.sum() / ok_number)
00100 self.func_data[theme_name]['ok_percent'].append(float(ok_number) / (pyimg.shape[0] * pyimg.shape[1]) / channels)
00101 self.func_data[theme_name]['num_channels'].append(channels)
00102 self.func_data[theme_name]['shape'].append(cv_image.shape)
00103 self.func_data[theme_name]['reported_size'].append((data.width, data.height, data.step))
00104 return _imageColorCallback
00105
00106 def imageDepthCallback(self, data):
00107 pass
00108
00109 def pointscloudCallback(self, theme_name):
00110 def _pointscloudCallback(data):
00111 self.prev_time = time.time()
00112 print 'Got pointcloud: %d, %d' % (data.width, data.height)
00113
00114 self.func_data[theme_name].setdefault('frame_counter', 0)
00115 self.func_data[theme_name].setdefault('avg', [])
00116 self.func_data[theme_name].setdefault('size', [])
00117 self.func_data[theme_name].setdefault('width', [])
00118 self.func_data[theme_name].setdefault('height', [])
00119
00120 self.func_data[theme_name]['frame_counter'] += 1
00121
00122 if self.func_data[theme_name]['frame_counter'] == 1:
00123
00124 return
00125
00126 try:
00127 points = np.array([pc2_to_xyzrgb(pp) for pp in pc2.read_points(data, skip_nans=True, field_names=("x", "y", "z", "rgb")) if pp[0] > 0])
00128 except Exception as e:
00129 print(e)
00130 return
00131 self.func_data[theme_name]['avg'].append(points.mean(0))
00132 self.func_data[theme_name]['size'].append(len(points))
00133 self.func_data[theme_name]['width'].append(data.width)
00134 self.func_data[theme_name]['height'].append(data.height)
00135 return _pointscloudCallback
00136
00137 def wait_for_message(self, params):
00138 topic = params['topic']
00139 print 'connect to ROS with name: %s' % self.node_name
00140 rospy.init_node(self.node_name, anonymous=True)
00141
00142 rospy.loginfo('Subscribing on topic: %s' % topic)
00143 self.sub = rospy.Subscriber(topic, msg_Image, self.callback)
00144
00145 self.prev_time = time.time()
00146 break_timeout = False
00147 while not any([rospy.core.is_shutdown(), break_timeout, self.result]):
00148 rospy.rostime.wallsleep(0.5)
00149 if self.timeout > 0 and time.time() - self.prev_time > self.timeout:
00150 break_timeout = True
00151 self.sub.unregister()
00152
00153 return self.result
00154
00155 @staticmethod
00156 def unregister_all(registers):
00157 for test_name in registers:
00158 rospy.loginfo('Un-Subscribing test %s' % test_name)
00159 registers[test_name]['sub'].unregister()
00160
00161 def wait_for_messages(self, themes):
00162
00163 self.func_data = dict([[theme_name, {}] for theme_name in themes])
00164
00165 print 'connect to ROS with name: %s' % self.node_name
00166 rospy.init_node(self.node_name, anonymous=True)
00167 for theme_name in themes:
00168 theme = self.themes[theme_name]
00169 rospy.loginfo('Subscribing %s on topic: %s' % (theme_name, theme['topic']))
00170 self.func_data[theme_name]['sub'] = rospy.Subscriber(theme['topic'], theme['msg_type'], theme['callback'](theme_name))
00171
00172 self.prev_time = time.time()
00173 break_timeout = False
00174 while not any([rospy.core.is_shutdown(), break_timeout]):
00175 rospy.rostime.wallsleep(0.5)
00176 if self.timeout > 0 and time.time() - self.prev_time > self.timeout:
00177 break_timeout = True
00178 self.unregister_all(self.func_data)
00179
00180 return self.func_data
00181
00182 def callback(self, data):
00183 rospy.loginfo('Got message. Seq %d, secs: %d, nsecs: %d' % (data.header.seq, data.header.stamp.secs, data.header.stamp.nsecs))
00184
00185 self.prev_time = time.time()
00186 if any([self.seq > 0 and data.header.seq >= self.seq,
00187 self.time and data.header.stamp.secs == self.time['secs'] and data.header.stamp.nsecs == self.time['nsecs']]):
00188 self.result = data
00189 self.sub.unregister()
00190
00191
00192
00193 def main():
00194 if len(sys.argv) < 2 or '--help' in sys.argv or '/?' in sys.argv:
00195 print 'USAGE:'
00196 print '------'
00197 print 'rs2_listener.py <topic | theme> [Options]'
00198 print 'example: rs2_listener.py /camera/color/image_raw --time 1532423022.044515610 --timeout 3'
00199 print 'example: rs2_listener.py pointscloud'
00200 print ''
00201 print 'Application subscribes on <topic>, wait for the first message matching [Options].'
00202 print 'When found, prints the timestamp.'
00203 print
00204 print '[Options:]'
00205 print '-s <sequential number>'
00206 print '--time <secs.nsecs>'
00207 print '--timeout <secs>'
00208 exit(-1)
00209
00210
00211
00212
00213 wanted_topic = sys.argv[1]
00214 msg_params = {}
00215 for idx in range(2, len(sys.argv)):
00216 if sys.argv[idx] == '-s':
00217 msg_params['seq'] = int(sys.argv[idx + 1])
00218 if sys.argv[idx] == '--time':
00219 msg_params['time'] = dict(zip(['secs', 'nsecs'], [int(part) for part in sys.argv[idx + 1].split('.')]))
00220 if sys.argv[idx] == '--timeout':
00221 msg_params['timeout_secs'] = int(sys.argv[idx + 1])
00222
00223 msg_retriever = CWaitForMessage(msg_params)
00224 if '/' in wanted_topic:
00225 msg_params = {'topic': wanted_topic}
00226 res = msg_retriever.wait_for_message(msg_params)
00227 rospy.loginfo('Got message: %s' % res.header)
00228 else:
00229 themes = [wanted_topic]
00230 res = msg_retriever.wait_for_messages(themes)
00231 print res
00232
00233
00234 if __name__ == '__main__':
00235 main()
00236