PointSampler library (C++)
Loading...
Searching...
No Matches
dbscan_clustering.hpp
Go to the documentation of this file.
1/* Copyright (c) 2025 Otto Link. Distributed under the terms of the GNU General
2 Public License. The full license is in the file LICENSE, distributed with
3 this software. */
4#pragma once
5#include <queue>
6
9
10namespace ps
11{
12
36template <typename T, size_t N>
37std::vector<int> dbscan_clustering(const std::vector<Point<T, N>> &points,
38 T eps,
39 size_t min_pts)
40{
41 if (points.empty())
42 return {};
43
44 PointCloudAdaptor<T, N> adaptor(points);
45 KDTree<T, N> index(N, adaptor);
46 index.buildIndex();
47
48 std::vector<int> labels(points.size(), -1); // -1 = unvisited/noise
49 int cluster_id = 0;
50
51 for (size_t i = 0; i < points.size(); ++i)
52 {
53 if (labels[i] != -1)
54 continue; // already assigned
55
56 // Query neighbors within radius
57 std::vector<nanoflann::ResultItem<unsigned int, T>> ret_matches;
58 nanoflann::SearchParameters params;
59 const T eps_sq = eps * eps;
60 std::array<T, N> query;
61 for (size_t d = 0; d < N; ++d)
62 query[d] = points[i][d];
63
64 index.radiusSearch(query.data(), eps_sq, ret_matches, params);
65
66 if (ret_matches.size() < min_pts)
67 {
68 labels[i] = -2; // mark as noise
69 continue;
70 }
71
72 // Start new cluster
73 labels[i] = cluster_id;
74
75 std::vector<size_t> seed_set;
76 seed_set.reserve(ret_matches.size());
77 for (auto &m : ret_matches)
78 if (m.first != i)
79 seed_set.push_back(m.first);
80
81 for (size_t j = 0; j < seed_set.size(); ++j)
82 {
83 size_t neighbor_idx = seed_set[j];
84 if (labels[neighbor_idx] == -2)
85 labels[neighbor_idx] = cluster_id; // was
86 // noise,
87 // now
88 // border
89 if (labels[neighbor_idx] != -1)
90 continue; // already
91 // assigned
92
93 labels[neighbor_idx] = cluster_id;
94
95 // Expand cluster if neighbor is a core
96 std::array<T, N> nq;
97 for (size_t d = 0; d < N; ++d)
98 nq[d] = points[neighbor_idx][d];
99 std::vector<nanoflann::ResultItem<unsigned int, T>> n_matches;
100 index.radiusSearch(nq.data(), eps_sq, n_matches, params);
101
102 if (n_matches.size() >= min_pts)
103 {
104 for (auto &nm : n_matches)
105 if (labels[nm.first] == -1)
106 seed_set.push_back(nm.first);
107 }
108 }
109
110 cluster_id++;
111 }
112
113 return labels;
114}
115
116} // namespace ps
Definition dbscan_clustering.hpp:11
std::vector< int > dbscan_clustering(const std::vector< Point< T, N > > &points, T eps, size_t min_pts)
Density-Based Spatial Clustering of Applications with Noise (DBSCAN).
Definition dbscan_clustering.hpp:37
nanoflann::KDTreeSingleIndexAdaptor< nanoflann::L2_Simple_Adaptor< T, PointCloudAdaptor< T, N > >, PointCloudAdaptor< T, N >, N > KDTree
Definition nanoflann_adaptator.hpp:35
Definition nanoflann_adaptator.hpp:13
A fixed-size N-dimensional point/vector class.
Definition point.hpp:39