00001
00002
00003 import roslib; roslib.load_manifest('projector_interface')
00004
00005 import ctypes
00006 import math
00007 import struct
00008 import numpy as np
00009 from scipy.sparse import lil_matrix
00010 from pycloud import PyCloud
00011
00012 from sensor_msgs.msg import PointCloud2, PointField
00013
00014 _DATATYPES = {}
00015 _DATATYPES[PointField.INT8] = ('b', 1)
00016 _DATATYPES[PointField.UINT8] = ('B', 1)
00017 _DATATYPES[PointField.INT16] = ('h', 2)
00018 _DATATYPES[PointField.UINT16] = ('H', 2)
00019 _DATATYPES[PointField.INT32] = ('i', 4)
00020 _DATATYPES[PointField.UINT32] = ('I', 4)
00021 _DATATYPES[PointField.FLOAT32] = ('f', 4)
00022 _DATATYPES[PointField.FLOAT64] = ('d', 8)
00023
00024 _NP_TYPES = {
00025 np.dtype('uint8') : (PointField.UINT8, 1),
00026 np.dtype('int8') : (PointField.INT8, 1),
00027 np.dtype('uint16') : (PointField.UINT16, 2),
00028 np.dtype('int16') : (PointField.INT16, 2),
00029 np.dtype('uint32') : (PointField.UINT32, 4),
00030 np.dtype('int32') : (PointField.INT32, 4),
00031 np.dtype('float32') : (PointField.FLOAT32,4),
00032 np.dtype('float64') : (PointField.FLOAT64,8)
00033 }
00034
00035 import time
00036
00037 def _float2rgb(x):
00038 rgb = struct.unpack('I', struct.pack('f', x))[0]
00039 b = (rgb >> 16) & 0x0000ff;
00040 g = (rgb >> 8) & 0x0000ff;
00041 r = (rgb) & 0x0000ff;
00042 return r,g,b
00043
00044 def float2rgb(farr):
00045 assert farr.ndim == 2
00046 out = np.zeros(farr.shape + (3,))
00047 for u, col in enumerate(farr):
00048 for v, val in enumerate(col):
00049 out[u,v,:] = _float2rgb(val)
00050 return out
00051
00052 def read_points_np(cloud, field_names=None, skip_nans=False, uvs=[], masked=True):
00053 reader = read_points(cloud, field_names=field_names, skip_nans=skip_nans, uvs=uvs)
00054 points = np.array(list(reader))
00055 reshaped = np.reshape(points, (cloud.height, cloud.width, len(cloud.fields)))
00056 if masked:
00057 return np.ma.masked_array(reshaped, np.isnan(reshaped))
00058 else:
00059 return reshaped
00060
00061 def read_points(cloud, field_names=None, skip_nans=False, uvs=[]):
00062 assert(cloud)
00063 fmt = _get_struct_fmt(cloud, field_names)
00064 width, height, point_step, row_step, data, isnan = cloud.width, cloud.height, cloud.point_step, cloud.row_step, cloud.data, math.isnan
00065 unpack_from = struct.Struct(fmt).unpack_from
00066
00067 if skip_nans:
00068 if uvs:
00069 for u, v in uvs:
00070 p = unpack_from(data, (row_step * v) + (point_step * u))
00071 has_nan = False
00072 for pv in p:
00073 if isnan(pv):
00074 has_nan = True
00075 break
00076 if not has_nan:
00077 yield p
00078 else:
00079 for v in xrange(height):
00080 offset = row_step * v
00081 for u in xrange(width):
00082 p = unpack_from(data, offset)
00083 has_nan = False
00084 for pv in p:
00085 if isnan(pv):
00086 has_nan = True
00087 break
00088 if not has_nan:
00089 yield p
00090 offset += point_step
00091 else:
00092 if uvs:
00093 for u, v in uvs:
00094 yield unpack_from(data, (row_step * v) + (point_step * u))
00095 else:
00096 for v in xrange(height):
00097 offset = row_step * v
00098 for u in xrange(width):
00099 yield unpack_from(data, offset)
00100 offset += point_step
00101
00102 def create_cloud_xyz32(header, points):
00103 fields = [PointField('x', 0, PointField.FLOAT32, 1),
00104 PointField('y', 4, PointField.FLOAT32, 1),
00105 PointField('z', 8, PointField.FLOAT32, 1)]
00106 return create_cloud(header, fields, points)
00107
00108 def np_to_point_list(cloud, fields):
00109 if cloud.ndim > 2:
00110 return cloud.reshape((np.prod(cloud.shape[:2]), len(fields)))
00111 else:
00112 return cloud
00113
00114 def create_cloud_np_xyz(points, header):
00115 dtype, width = _NP_TYPES[points.dtype]
00116 fields = [PointField('x', width*0, dtype, 1),
00117 PointField('y', width*1, dtype, 1),
00118 PointField('z', width*2, dtype, 1)]
00119 return create_cloud_np(header, fields, points)
00120
00121
00122 def create_cloud_np(header, fields, points):
00123 return create_cloud(header, fields, np_to_point_list(points, fields), points.shape)
00124
00125 def create_cloud(header, fields, points, shape=None):
00126 cloud = PointCloud2()
00127 cloud.header = header
00128 cloud.height = 1
00129 cloud.width = len(points)
00130 cloud.is_dense = False
00131 cloud.is_bigendian = False
00132 cloud.fields = fields
00133 fmt = _get_struct_fmt(cloud)
00134 cloud_struct = struct.Struct(fmt)
00135 cloud.point_step = cloud_struct.size
00136 cloud.row_step = cloud_struct.size * cloud.width
00137
00138 buffer = ctypes.create_string_buffer(cloud_struct.size * cloud.width)
00139
00140 point_step, pack_into = cloud.point_step, cloud_struct.pack_into
00141 offset = 0
00142 for p in points:
00143 if not np.ma.is_masked(p):
00144 pack_into(buffer, offset, *p)
00145 offset += point_step
00146
00147 cloud.data = buffer.raw
00148
00149
00150
00151 return cloud
00152
00153 def _create_point_field(cloud, field_names=None):
00154 nFields = cloud.shape[2]
00155 if not field_names:
00156 if nFields == 3:
00157 field_names = ['x','y','z']
00158 elif nFields == 4:
00159 field_names = ['x','y','z','index']
00160 elif nFields == 6:
00161 field_names = ['x','y','z','r','g','b']
00162
00163 fields = []
00164 for field_name in field_names:
00165 field = PointField()
00166
00167 def _get_struct_fmt(cloud, field_names=None):
00168 fmt = '>' if cloud.is_bigendian else '<'
00169 offset = 0
00170 for field in (f for f in sorted(cloud.fields, key=lambda f: f.offset) if field_names is None or f.name in field_names):
00171 if offset < field.offset:
00172 fmt += 'x' * (field.offset - offset)
00173 offset = field.offset
00174 if field.datatype not in _DATATYPES:
00175 print >> sys.stderr, 'Skipping unknown PointField datatype [%d]' % field.datatype
00176 else:
00177 datatype_fmt, datatype_length = _DATATYPES[field.datatype]
00178 fmt += field.count * datatype_fmt
00179 offset += field.count * datatype_length
00180
00181 return fmt