ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ISSKeypoint.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 // @author Ignacio Vizzo [ivizzo@uni-bonn.de]
8 //
9 // Copyright (c) 2020 Ignacio Vizzo, Cyrill Stachniss, University of Bonn.
10 // ----------------------------------------------------------------------------
11 
12 #include "ISSKeypoint.h"
13 
14 #include <Eigen.h>
15 #include <Logging.h>
16 
17 #include <Eigen/Core>
18 #include <Eigen/Eigenvalues>
19 #include <cmath>
20 #include <memory>
21 #include <tuple>
22 #include <vector>
23 
24 #include "ecvKDTreeFlann.h"
25 #include "ecvPointCloud.h"
26 
27 namespace cloudViewer {
28 
29 namespace {
30 
31 bool IsLocalMaxima(int query_idx,
32  const std::vector<int>& indices,
33  const std::vector<double>& third_eigen_values) {
34  for (const auto& idx : indices) {
35  if (third_eigen_values[query_idx] < third_eigen_values[idx]) {
36  return false;
37  }
38  }
39  return true;
40 }
41 
42 double ComputeModelResolution(const std::vector<Eigen::Vector3d>& points,
43  const geometry::KDTreeFlann& kdtree) {
44  std::vector<int> indices(2);
45  std::vector<double> distances(2);
46  double resolution = 0.0;
47 
48  for (const auto& point : points) {
49  if (kdtree.SearchKNN(point, 2, indices, distances) != 0) {
50  resolution += std::sqrt(distances[1]);
51  }
52  }
53  resolution /= points.size();
54  return resolution;
55 }
56 
57 } // namespace
58 
59 namespace geometry {
60 namespace keypoint {
61 
62 std::shared_ptr<ccPointCloud> ComputeISSKeypoints(
63  const ccPointCloud& input,
64  double salient_radius /* = 0.0 */,
65  double non_max_radius /* = 0.0 */,
66  double gamma_21 /* = 0.975 */,
67  double gamma_32 /* = 0.975 */,
68  int min_neighbors /*= 5 */) {
69  if (input.IsEmpty()) {
71  "[ComputeISSKeypoints] Input ccPointCloud is empty!");
72  return std::make_shared<ccPointCloud>();
73  }
74  const auto& points = input.getEigenPoints();
75  KDTreeFlann kdtree(input);
76 
77  if (salient_radius == 0.0 || non_max_radius == 0.0) {
78  const double resolution = ComputeModelResolution(points, kdtree);
79  salient_radius = 6 * resolution;
80  non_max_radius = 4 * resolution;
82  "[ComputeISSKeypoints] Computed salient_radius = {}, "
83  "non_max_radius = {} from input model",
84  salient_radius, non_max_radius);
85  }
86 
87  std::vector<double> third_eigen_values(points.size());
88 #pragma omp parallel for schedule(static) shared(third_eigen_values)
89  for (int i = 0; i < (int)points.size(); i++) {
90  std::vector<int> indices;
91  std::vector<double> dist;
92  int nb_neighbors =
93  kdtree.SearchRadius(points[i], salient_radius, indices, dist);
94  if (nb_neighbors < min_neighbors) {
95  continue;
96  }
97 
98  Eigen::Matrix3d cov =
100  if (cov.isZero()) {
101  continue;
102  }
103 
104  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> solver(cov);
105  const double& e1c = solver.eigenvalues()[2];
106  const double& e2c = solver.eigenvalues()[1];
107  const double& e3c = solver.eigenvalues()[0];
108 
109  if ((e2c / e1c) < gamma_21 && e3c / e2c < gamma_32) {
110  third_eigen_values[i] = e3c;
111  }
112  }
113 
114  std::vector<size_t> kp_indices;
115  kp_indices.reserve(points.size());
116 #pragma omp parallel for schedule(static) shared(kp_indices)
117  for (int i = 0; i < (int)points.size(); i++) {
118  if (third_eigen_values[i] > 0.0) {
119  std::vector<int> nn_indices;
120  std::vector<double> dist;
121  int nb_neighbors = kdtree.SearchRadius(points[i], non_max_radius,
122  nn_indices, dist);
123 
124  if (nb_neighbors >= min_neighbors &&
125  IsLocalMaxima(i, nn_indices, third_eigen_values)) {
126  kp_indices.emplace_back(i);
127  }
128  }
129  }
130 
132  "[ComputeISSKeypoints] Extracted {} keypoints", kp_indices.size());
133  return input.SelectByIndex(kp_indices);
134 }
135 
136 } // namespace keypoint
137 } // namespace geometry
138 } // namespace cloudViewer
int points
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
virtual bool IsEmpty() const override
std::shared_ptr< ccPointCloud > SelectByIndex(const std::vector< size_t > &indices, bool invert=false) const
Function to select points from input ccPointCloud into output ccPointCloud.
std::vector< Eigen::Vector3d > getEigenPoints() const
KDTree with FLANN for nearest neighbor search.
int SearchRadius(const T &query, double radius, std::vector< int > &indices, std::vector< double > &distance2) const
#define LogWarning(...)
Definition: Logging.h:72
#define LogDebug(...)
Definition: Logging.h:90
std::shared_ptr< ccPointCloud > ComputeISSKeypoints(const ccPointCloud &input, double salient_radius=0.0, double non_max_radius=0.0, double gamma_21=0.975, double gamma_32=0.975, int min_neighbors=5)
Function that computes the ISS Keypoints from an input point cloud. This implements the keypoint dete...
Definition: ISSKeypoint.cpp:62
Eigen::Matrix3d ComputeCovariance(const std::vector< Eigen::Vector3d > &points, const std::vector< IdxType > &indices)
Function to compute the covariance matrix of a set of points.
Definition: Eigen.cpp:287
Generic file read and write utility for python interface.