Skip to content

DBSCAN Clustering

After GnC, each real cone still produces many returns, and noise remains. Downstream coloring and planning want one 3D point per cone. DBSCAN groups nearby returns and emits the mean of each dense cluster.

Neighbor search is in the horizontal plane only: distance uses (x,y)(x,y), not zz. That matches cones as vertical objects with noisy height.

For each unvisited point:

  1. Collect neighbors within radius ε\varepsilon (epsilon, default about 200 mm internally).
  2. If the neighbor count is at least min_points, grow a cluster through dense unvisited neighbors.
  3. Points that never meet min_points are discarded as noise.
  4. Centroid =mean(x,y,z)= \mathrm{mean}(x,y,z) in millimetres; publish path converts to metres on /cones.

Search is O(n2)O(n^2) without a spatial index. GnC (and cutoffs) keep nn small enough for the frame budget. A KD-tree path has been discussed; it is not the default.

A second pass over centroids with a larger ε2\varepsilon_2 can drop isolated false-positive centroids.

  • prod: call site usually commented; dbscan2_on=false by default.
  • lidar-dev: live when dbscan2_on; epsilon2 often about 4 m.
ParameterDefaultNotes
epsilon~200 mmNeighbor radius for primary clustering
min_points2Minimum returns to form a cluster
dbscan2_onfalseEnable centroid second pass
epsilon2~4 m on lidar-devSecond-pass neighbor radius
SymptomLikely cause
Ground-filtered shows cone blobs, /cones empty or sparsemin_points too high or epsilon too small
Two cones merged into one centroidepsilon too large
Many singleton false conesmin_points too low; consider DBSCAN2 on lidar-dev
High /lidar/log process time with loose cutoffsToo many points reaching DBSCAN

frame_processor.cpp (DBSCAN, expand_cluster, computeCentroids). Upstream filter: GnC. Driver overview: LiDAR driver.