Skip to content
This repository was archived by the owner on Dec 30, 2023. It is now read-only.

Commit ef538e7

Browse files
committed
optimize some methods that call at
Using pointers to work around broken C++ reference support in Cython. operator[] seems to be completely broken in Cython. E.g. >>> a = np.random.randn(10000, 3).astype(np.float32) >>> p = PointCloud() >>> p.from_array(a) >>> %timeit p.to_array() 10000 loops, best of 3: 23.4 µs per loop Previously 50.8 µs per loop.
1 parent b12f641 commit ef538e7

File tree

1 file changed

+22
-27
lines changed

1 file changed

+22
-27
lines changed

pcl.pyx

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ cimport numpy as cnp
66

77
cimport pcl_defs as cpp
88

9+
cimport cython
910
from cython.operator import dereference as deref
1011
from libcpp.string cimport string
1112
from libcpp cimport bool
@@ -138,6 +139,7 @@ cdef class PointCloud:
138139
""" property containing whether the cloud is dense or not """
139140
def __get__(self): return self.thisptr.is_dense
140141

142+
@cython.boundscheck(False)
141143
def from_array(self, cnp.ndarray[cnp.float32_t, ndim=2] arr not None):
142144
"""
143145
Fill this object from a 2D numpy array (float32)
@@ -149,43 +151,43 @@ cdef class PointCloud:
149151
self.thisptr.width = npts
150152
self.thisptr.height = 1
151153

154+
cdef cpp.PointXYZ *p
152155
for i in range(npts):
153-
self.thisptr.at(i).x = arr[i,0]
154-
self.thisptr.at(i).y = arr[i,1]
155-
self.thisptr.at(i).z = arr[i,2]
156+
p = &self.thisptr.at(i)
157+
p.x, p.y, p.z = arr[i, 0], arr[i, 1], arr[i, 2]
156158

159+
@cython.boundscheck(False)
157160
def to_array(self):
158161
"""
159162
Return this object as a 2D numpy array (float32)
160163
"""
161164
cdef float x,y,z
162165
cdef cnp.npy_intp n = self.thisptr.size()
163-
cdef cnp.ndarray[float, ndim=2] result = np.empty([n,3], dtype=np.float32)
166+
cdef cnp.ndarray[cnp.float32_t, ndim=2, mode="c"] result
167+
cdef cpp.PointXYZ *p
168+
169+
result = np.empty((n, 3), dtype=np.float32)
164170

165171
for i in range(n):
166-
x = self.thisptr.at(i).x
167-
y = self.thisptr.at(i).y
168-
z = self.thisptr.at(i).z
169-
result[i,0] = x
170-
result[i,1] = y
171-
result[i,2] = z
172+
p = &self.thisptr.at(i)
173+
result[i, 0] = p.x
174+
result[i, 1] = p.y
175+
result[i, 2] = p.z
172176
return result
173177

174178
def from_list(self, _list):
175179
"""
176180
Fill this pointcloud from a list of 3-tuples
177181
"""
178-
assert len(_list)
179-
assert len(_list[0]) == 3
180-
181182
cdef Py_ssize_t npts = len(_list)
183+
cdef cpp.PointXYZ *p
184+
182185
self.resize(npts)
183186
self.thisptr.width = npts
184187
self.thisptr.height = 1
185188
for i,l in enumerate(_list):
186-
self.thisptr.at(i).x = l[0]
187-
self.thisptr.at(i).y = l[1]
188-
self.thisptr.at(i).z = l[2]
189+
p = &self.thisptr.at(i)
190+
p.x, p.y, p.z = l
189191

190192
def to_list(self):
191193
"""
@@ -200,19 +202,12 @@ cdef class PointCloud:
200202
"""
201203
Return a point (3-tuple) at the given row/column
202204
"""
203-
#grr.... the following doesnt compile to valid
204-
#cython.. so just take the perf hit
205-
#cdef PointXYZ &p = self.thisptr.at(x,y)
206-
cdef x = self.thisptr.at(row,col).x
207-
cdef y = self.thisptr.at(row,col).y
208-
cdef z = self.thisptr.at(row,col).z
209-
return x,y,z
205+
cdef cpp.PointXYZ *p = &self.thisptr.at(row, col)
206+
return p.x, p.y, p.z
210207

211208
def __getitem__(self, cnp.npy_intp idx):
212-
cdef x = self.thisptr.at(idx).x
213-
cdef y = self.thisptr.at(idx).y
214-
cdef z = self.thisptr.at(idx).z
215-
return x,y,z
209+
cdef cpp.PointXYZ *p = &self.thisptr.at(idx)
210+
return p.x, p.y, p.z
216211

217212
def from_file(self, char *f):
218213
"""

0 commit comments

Comments
 (0)