Skip to content

Commit 81fa508

Browse files
committed
Port pointcloud creation to numpy.
1 parent 105e831 commit 81fa508

File tree

2 files changed

+35
-41
lines changed

2 files changed

+35
-41
lines changed

sensor_msgs_py/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<author email="sebastian.grans@gmail.com">Sebastian Grans</author>
1616

1717
<exec_depend>sensor_msgs</exec_depend>
18+
<exec_depend>python3-numpy</exec_depend>
1819

1920
<test_depend>ament_copyright</test_depend>
2021
<test_depend>ament_flake8</test_depend>

sensor_msgs_py/sensor_msgs_py/point_cloud2.py

Lines changed: 34 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import math
4343
import struct
4444
import sys
45+
import numpy as np
4546

4647
from sensor_msgs.msg import PointCloud2, PointField
4748

@@ -144,40 +145,6 @@ def read_points_list(cloud, field_names=None, skip_nans=False, uvs=[]):
144145
skip_nans, uvs)]
145146

146147

147-
def create_cloud(header, fields, points):
148-
"""
149-
Create a sensor_msgs.msg.PointCloud2 message.
150-
151-
:param header: The point cloud header. (Type: std_msgs.msg.Header)
152-
:param fields: The point cloud fields.
153-
(Type: iterable of sensor_msgs.msg.PointField)
154-
:param points: The point cloud points. List of iterables, i.e. one iterable
155-
for each point, with the elements of each iterable being the
156-
values of the fields for that point (in the same order as
157-
the fields parameter)
158-
:return: The point cloud as sensor_msgs.msg.PointCloud2
159-
"""
160-
cloud_struct = struct.Struct(_get_struct_fmt(False, fields))
161-
162-
buff = ctypes.create_string_buffer(cloud_struct.size * len(points))
163-
164-
point_step, pack_into = cloud_struct.size, cloud_struct.pack_into
165-
offset = 0
166-
for p in points:
167-
pack_into(buff, offset, *p)
168-
offset += point_step
169-
170-
return PointCloud2(header=header,
171-
height=1,
172-
width=len(points),
173-
is_dense=False,
174-
is_bigendian=False,
175-
fields=fields,
176-
point_step=cloud_struct.size,
177-
row_step=cloud_struct.size * len(points),
178-
data=buff.raw)
179-
180-
181148
def create_cloud_xyz32(header, points):
182149
"""
183150
Create a sensor_msgs.msg.PointCloud2 message with (x, y, z) fields.
@@ -186,13 +153,39 @@ def create_cloud_xyz32(header, points):
186153
:param points: The point cloud points. (Type: Iterable)
187154
:return: The point cloud as sensor_msgs.msg.PointCloud2.
188155
"""
189-
fields = [PointField(name='x', offset=0,
190-
datatype=PointField.FLOAT32, count=1),
191-
PointField(name='y', offset=4,
192-
datatype=PointField.FLOAT32, count=1),
193-
PointField(name='z', offset=8,
194-
datatype=PointField.FLOAT32, count=1)]
195-
return create_cloud(header, fields, points)
156+
# Convert to numpy if it isn't already
157+
points = np.asarray(points)
158+
# Convert data to f32, flatten it and cat it to a byte string
159+
data = points.astype(np.float32).reshape(-1).tobytes()
160+
# Define offsets
161+
point_value_bits = 32 # float32
162+
point_num_values = 3 # 3 values are a point
163+
point_value_bytes = point_value_bits // 8 # Number of bytes used for one value
164+
point_bytes = (point_num_values * point_value_bits) // 8 # Bytes used by one point
165+
166+
# This function generates a point field describing the stored raw data for one dimension
167+
def make_point_field(element):
168+
i = element[0]
169+
name = element[1]
170+
return PointField(
171+
name = name,
172+
offset = i * point_value_bytes,
173+
datatype = PointField.FLOAT32,
174+
count = 1)
175+
176+
# Make a point field for each of the major axis
177+
fields = list(map(make_point_field, enumerate(['x', 'y', 'z'])))
178+
# Put everything together
179+
return PointCloud2(
180+
header = header,
181+
height = 1,
182+
width = len(points),
183+
is_dense = False,
184+
is_bigendian = False,
185+
fields = fields,
186+
point_step = point_bytes,
187+
row_step = point_bytes * len(points),
188+
data = data)
196189

197190

198191
def _get_struct_fmt(is_bigendian, fields, field_names=None):

0 commit comments

Comments
 (0)