Skip to content

Commit fd7a877

Browse files
authored
Merge pull request #3 from UrbanMachine/rolling
Improve speed of `msgify(point_cloud_2_np)` by 115x
2 parents 238b6a2 + 0e6886e commit fd7a877

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

ros2_numpy/point_cloud2.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
from .registry import converts_from_numpy, converts_to_numpy
4141

42+
import array
4243
import numpy as np
4344
from sensor_msgs.msg import PointCloud2, PointField
4445

@@ -165,7 +166,21 @@ def array_to_pointcloud2(cloud_arr, stamp=None, frame_id=None):
165166
cloud_msg.is_dense = \
166167
all([np.isfinite(
167168
cloud_arr[fname]).all() for fname in cloud_arr.dtype.names])
168-
cloud_msg.data = cloud_arr.tostring()
169+
170+
# The PointCloud2.data setter will create an array.array object for you if you don't
171+
# provide it one directly. This causes very slow performance because it iterates
172+
# over each byte in python.
173+
# Here we create an array.array object using a memoryview, limiting copying and
174+
# increasing performance.
175+
memory_view = memoryview(cloud_arr)
176+
if memory_view.nbytes > 0:
177+
array_bytes = memory_view.cast("B")
178+
else:
179+
# Casting raises a TypeError if the array has no elements
180+
array_bytes = b""
181+
as_array = array.array("B")
182+
as_array.frombytes(array_bytes)
183+
cloud_msg.data = as_array
169184
return cloud_msg
170185

171186
def merge_rgb_fields(cloud_arr):

test/test_pointclouds.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,19 @@ def test_roundtrip(self):
7575
np.testing.assert_equal(points_arr, new_points_arr)
7676

7777
def test_roundtrip_numpy(self):
78-
7978
points_arr = self.makeArray(100)
8079
cloud_msg = rnp.msgify(PointCloud2, points_arr)
8180
new_points_arr = rnp.numpify(cloud_msg)
8281

8382
np.testing.assert_equal(points_arr, new_points_arr)
8483

84+
def test_roundtrip_zero_points(self):
85+
"""Test to make sure zero point arrays don't raise memoryview.cast(*) errors"""
86+
points_arr = self.makeArray(0)
87+
cloud_msg = rnp.msgify(PointCloud2, points_arr)
88+
new_points_arr = rnp.numpify(cloud_msg)
89+
90+
np.testing.assert_equal(points_arr, new_points_arr)
91+
8592
if __name__ == '__main__':
8693
unittest.main()

0 commit comments

Comments
 (0)