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

Commit dea63de

Browse files
committed
improve KdTreeFLANN API and test it
Previously, constructing a KdTreeFLANN object made no sense since there was no way to set its input cloud. It would segfault at first use.
1 parent da50cdd commit dea63de

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

examples/kdtree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
pc_1.from_array(points_1)
1919
pc_2 = pcl.PointCloud()
2020
pc_2.from_array(points_2)
21-
kd = pc_1.make_kdtree_flann()
21+
kd = pcl.KdTreeFLANN(pc_1)
2222
# find the single closest points to each point in point cloud 2
2323
# (and the sqr distances)
2424
indices, sqr_distances = kd.nearest_k_search_for_cloud(pc_2, 1)

pcl/_pcl.pyx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -341,12 +341,10 @@ cdef class PointCloud:
341341
def make_kdtree_flann(self):
342342
"""
343343
Return a pcl.kdTreeFLANN object with this object set as the input-cloud
344+
345+
Deprecated: use the pcl.KdTreeFLANN constructor on this cloud.
344346
"""
345-
kdtree = KdTreeFLANN()
346-
cdef cpp.KdTreeFLANN_t *ckdtree = <cpp.KdTreeFLANN_t *>kdtree.me
347-
cdef cpp.PointCloud_t *ccloud = <cpp.PointCloud_t *>self.thisptr
348-
ckdtree.setInputCloud(ccloud.makeShared())
349-
return kdtree
347+
return KdTreeFLANN(self)
350348

351349
def make_octree(self, double resolution):
352350
"""
@@ -510,11 +508,20 @@ cdef class PassThroughFilter:
510508
cdef class KdTreeFLANN:
511509
"""
512510
Finds k nearest neighbours from points in another pointcloud to points in
513-
this pointcloud
511+
a reference pointcloud.
512+
513+
Must be constructed from the reference point cloud, which is copied, so
514+
changed to pc are not reflected in KdTreeFLANN(pc).
514515
"""
515516
cdef cpp.KdTreeFLANN_t *me
516-
def __cinit__(self):
517+
518+
def __cinit__(self, PointCloud pc):
519+
# XXX it seems copying the entire pointcloud is the only option in
520+
# PCL 1.7.1.
521+
cdef cpp.PointCloud_t *ccloud = <cpp.PointCloud_t *>pc.thisptr
517522
self.me = new cpp.KdTreeFLANN_t()
523+
self.me.setInputCloud(ccloud.makeShared())
524+
518525
def __dealloc__(self):
519526
del self.me
520527

tests/test.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,37 @@ def testFilterBoth(self):
298298
back = fil.filter().size
299299
self.assertEqual(total,front+back)
300300

301+
class TestKdTree(unittest.TestCase):
302+
def setUp(self):
303+
rng = np.random.RandomState(42)
304+
# Define two dense sets of points of sizes 30 and 170, resp.
305+
a = np.random.randn(100, 3).astype(np.float32)
306+
a[:30] -= 42
307+
308+
self.pc = pcl.PointCloud(a)
309+
self.kd = pcl.KdTreeFLANN(self.pc)
310+
311+
def testException(self):
312+
self.assertRaises(TypeError, pcl.KdTreeFLANN)
313+
314+
def testKNN(self):
315+
# Small cluster
316+
ind, sqdist = self.kd.nearest_k_search_for_point(self.pc, 0, k=2)
317+
for i in ind:
318+
self.assertGreaterEqual(i, 0)
319+
self.assertLess(i, 30)
320+
for d in sqdist:
321+
self.assertGreaterEqual(d, 0)
322+
323+
# Big cluster
324+
for ref, k in ((80, 1), (59, 3), (60, 10)):
325+
ind, sqdist = self.kd.nearest_k_search_for_point(self.pc, ref, k=k)
326+
for i in ind:
327+
self.assertGreaterEqual(i, 0)
328+
self.assertGreaterEqual(i, 30)
329+
for d in sqdist:
330+
self.assertGreaterEqual(d, 0)
331+
301332
class TestOctreePointCloud(unittest.TestCase):
302333
def setUp(self):
303334
self.t = pcl.OctreePointCloud(0.1)

0 commit comments

Comments
 (0)