38 #ifndef PCL_ISS_KEYPOINT3D_IMPL_H_
39 #define PCL_ISS_KEYPOINT3D_IMPL_H_
41 #include <Eigen/Eigenvalues>
42 #include <pcl/features/boundary.h>
43 #include <pcl/features/normal_3d.h>
44 #include <pcl/features/integral_image_normal.h>
46 #include <pcl/keypoints/iss_3d.h>
49 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
52 salient_radius_ = salient_radius;
56 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
59 non_max_radius_ = non_max_radius;
63 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
66 normal_radius_ = normal_radius;
70 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
73 border_radius_ = border_radius;
77 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
84 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
91 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
94 min_neighbors_ = min_neighbors;
98 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
105 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
110 threads_ = omp_get_num_procs();
115 threads_ = nr_threads;
119 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
bool*
122 bool* edge_points =
new bool [input.size ()];
124 Eigen::Vector4f u = Eigen::Vector4f::Zero ();
125 Eigen::Vector4f v = Eigen::Vector4f::Zero ();
130 #pragma omp parallel for \
132 shared(angle_threshold, boundary_estimator, border_radius, edge_points, input) \
134 num_threads(threads_)
135 for (
int index = 0; index < static_cast<int>(input.size ()); index++)
137 edge_points[index] =
false;
138 PointInT current_point = input[index];
143 std::vector<float> nn_distances;
146 this->searchForNeighbors (index, border_radius, nn_indices, nn_distances);
148 n_neighbors =
static_cast<int> (nn_indices.size ());
150 if (n_neighbors >= min_neighbors_)
154 if (boundary_estimator.
isBoundaryPoint (input,
static_cast<int> (index), nn_indices, u, v, angle_threshold))
155 edge_points[index] =
true;
160 return (edge_points);
164 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
167 const PointInT& current_point = (*input_)[current_index];
169 double central_point[3]{};
171 central_point[0] = current_point.x;
172 central_point[1] = current_point.y;
173 central_point[2] = current_point.z;
175 cov_m = Eigen::Matrix3d::Zero ();
178 std::vector<float> nn_distances;
181 this->searchForNeighbors (current_index, salient_radius_, nn_indices, nn_distances);
183 n_neighbors =
static_cast<int> (nn_indices.size ());
185 if (n_neighbors < min_neighbors_)
190 for (
const auto& n_idx : nn_indices)
192 const PointInT& n_point = (*input_)[n_idx];
194 double neigh_point[3]{};
196 neigh_point[0] = n_point.x;
197 neigh_point[1] = n_point.y;
198 neigh_point[2] = n_point.z;
200 for (
int i = 0; i < 3; i++)
201 for (
int j = 0; j < 3; j++)
202 cov[i * 3 + j] += (neigh_point[i] - central_point[i]) * (neigh_point[j] - central_point[j]);
205 cov_m << cov[0], cov[1], cov[2],
206 cov[3], cov[4], cov[5],
207 cov[6], cov[7], cov[8];
211 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
bool
216 PCL_ERROR (
"[pcl::%s::initCompute] init failed!\n", name_.c_str ());
219 if (salient_radius_ <= 0)
221 PCL_ERROR (
"[pcl::%s::initCompute] : the salient radius (%f) must be strict positive!\n",
222 name_.c_str (), salient_radius_);
225 if (non_max_radius_ <= 0)
227 PCL_ERROR (
"[pcl::%s::initCompute] : the non maxima radius (%f) must be strict positive!\n",
228 name_.c_str (), non_max_radius_);
233 PCL_ERROR (
"[pcl::%s::initCompute] : the threshold on the ratio between the 2nd and the 1rst eigenvalue (%f) must be strict positive!\n",
234 name_.c_str (), gamma_21_);
239 PCL_ERROR (
"[pcl::%s::initCompute] : the threshold on the ratio between the 3rd and the 2nd eigenvalue (%f) must be strict positive!\n",
240 name_.c_str (), gamma_32_);
243 if (min_neighbors_ <= 0)
245 PCL_ERROR (
"[pcl::%s::initCompute] : the minimum number of neighbors (%f) must be strict positive!\n",
246 name_.c_str (), min_neighbors_);
250 delete[] third_eigen_value_;
252 third_eigen_value_ =
new double[input_->size ()]{};
254 delete[] edge_points_;
256 if (border_radius_ > 0.0)
258 if (normals_->empty ())
260 if (normal_radius_ <= 0.)
262 PCL_ERROR (
"[pcl::%s::initCompute] : the radius used to estimate surface normals (%f) must be positive!\n",
263 name_.c_str (), normal_radius_);
268 if (input_->height == 1 )
273 normal_estimation.
compute (*normal_ptr);
281 normal_estimation.
compute (*normal_ptr);
283 normals_ = normal_ptr;
285 if (normals_->size () != surface_->size ())
287 PCL_ERROR (
"[pcl::%s::initCompute] normals given, but the number of normals does not match the number of input points!\n", name_.c_str ());
291 else if (border_radius_ < 0.0)
293 PCL_ERROR (
"[pcl::%s::initCompute] : the border radius used to estimate boundary points (%f) must be positive!\n",
294 name_.c_str (), border_radius_);
302 template<
typename Po
intInT,
typename Po
intOutT,
typename NormalT>
void
308 if (border_radius_ > 0.0)
309 edge_points_ = getBoundaryPoints (*(input_->makeShared ()), border_radius_, angle_threshold_);
311 bool* borders =
new bool [input_->size()];
313 #pragma omp parallel for \
316 num_threads(threads_)
317 for (
int index = 0; index < static_cast<int>(input_->size ()); index++)
319 borders[index] =
false;
320 PointInT current_point = (*input_)[index];
322 if ((border_radius_ > 0.0) && (
pcl::isFinite(current_point)))
325 std::vector<float> nn_distances;
327 this->searchForNeighbors (index, border_radius_, nn_indices, nn_distances);
329 for (
const auto &nn_index : nn_indices)
331 if (edge_points_[nn_index])
333 borders[index] =
true;
341 auto *omp_mem =
new Eigen::Vector3d[threads_];
343 for (std::size_t i = 0; i < threads_; i++)
344 omp_mem[i].setZero (3);
346 auto *omp_mem =
new Eigen::Vector3d[1];
348 omp_mem[0].setZero (3);
351 double *prg_local_mem =
new double[input_->size () * 3];
352 double **prg_mem =
new double * [input_->size ()];
354 for (std::size_t i = 0; i < input_->size (); i++)
355 prg_mem[i] = prg_local_mem + 3 * i;
357 #pragma omp parallel for \
359 shared(borders, omp_mem, prg_mem) \
360 num_threads(threads_)
361 for (
int index = 0; index < static_cast<int> (input_->size ()); index++)
364 int tid = omp_get_thread_num ();
368 PointInT current_point = (*input_)[index];
373 Eigen::Matrix3d cov_m = Eigen::Matrix3d::Zero ();
374 getScatterMatrix (
static_cast<int> (index), cov_m);
376 const Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> solver (cov_m, Eigen::EigenvaluesOnly);
378 const double& e1c = solver.eigenvalues ()[2];
379 const double& e2c = solver.eigenvalues ()[1];
380 const double& e3c = solver.eigenvalues ()[0];
382 if (!std::isfinite (e1c) || !std::isfinite (e2c) || !std::isfinite (e3c))
387 PCL_WARN (
"[pcl::%s::detectKeypoints] : The third eigenvalue is negative! Skipping the point with index %i.\n",
388 name_.c_str (), index);
392 omp_mem[tid][0] = e2c / e1c;
393 omp_mem[tid][1] = e3c / e2c;
394 omp_mem[tid][2] = e3c;
397 for (Eigen::Index d = 0; d < omp_mem[tid].size (); d++)
398 prg_mem[index][d] = omp_mem[tid][d];
401 for (
int index = 0; index < static_cast<int>(input_->size ()); index++)
405 if ((prg_mem[index][0] < gamma_21_) && (prg_mem[index][1] < gamma_32_))
406 third_eigen_value_[index] = prg_mem[index][2];
410 bool* feat_max =
new bool [input_->size()];
412 #pragma omp parallel for \
415 num_threads(threads_)
416 for (
int index = 0; index < static_cast<int>(input_->size ()); index++)
418 feat_max [index] =
false;
419 PointInT current_point = (*input_)[index];
421 if ((third_eigen_value_[index] > 0.0) && (
pcl::isFinite(current_point)))
424 std::vector<float> nn_distances;
427 this->searchForNeighbors (index, non_max_radius_, nn_indices, nn_distances);
429 n_neighbors =
static_cast<int> (nn_indices.size ());
431 if (n_neighbors >= min_neighbors_)
435 for (
const auto& j : nn_indices)
436 if (third_eigen_value_[index] < third_eigen_value_[j])
439 feat_max[index] =
true;
444 #pragma omp parallel for \
446 shared(feat_max, output) \
447 num_threads(threads_)
448 for (
int index = 0; index < static_cast<int>(input_->size ()); index++)
454 p.getVector3fMap () = (*input_)[index].getVector3fMap ();
456 keypoints_indices_->indices.push_back (index);
460 output.header = input_->header;
461 output.width = output.size ();
465 if (border_radius_ > 0.0)
470 delete[] prg_local_mem;
475 #define PCL_INSTANTIATE_ISSKeypoint3D(T,U,N) template class PCL_EXPORTS pcl::ISSKeypoint3D<T,U,N>;
BoundaryEstimation estimates whether a set of points is lying on surface boundaries using an angle cr...
bool isBoundaryPoint(const pcl::PointCloud< PointInT > &cloud, int q_idx, const pcl::Indices &indices, const Eigen::Vector4f &u, const Eigen::Vector4f &v, const float angle_threshold) const
Check whether a point is a boundary point in a planar patch of projected points given by indices.
void getCoordinateSystemOnPlane(const PointNT &p_coeff, Eigen::Vector4f &u, Eigen::Vector4f &v) const
Get a u-v-n coordinate system that lies on a plane defined by its normal.
void setRadiusSearch(double radius)
Set the sphere radius that is to be used for determining the nearest neighbors used for the feature e...
void compute(PointCloudOut &output)
Base method for feature estimation for all points given in <setInputCloud (), setIndices ()> using th...
typename PointCloudN::ConstPtr PointCloudNConstPtr
void setNumberOfThreads(unsigned int nr_threads=0)
Initialize the scheduler and set the number of threads to use.
typename Keypoint< PointInT, PointOutT >::PointCloudIn PointCloudIn
void setNormals(const PointCloudNConstPtr &normals)
Set the normals if pre-calculated normals are available.
void setBorderRadius(double border_radius)
Set the radius used for the estimation of the boundary points.
void setSalientRadius(double salient_radius)
Set the radius of the spherical neighborhood used to compute the scatter matrix.
void getScatterMatrix(const int ¤t_index, Eigen::Matrix3d &cov_m)
Compute the scatter matrix for a point index.
void setThreshold21(double gamma_21)
Set the upper bound on the ratio between the second and the first eigenvalue.
void setMinNeighbors(int min_neighbors)
Set the minimum number of neighbors that has to be found while applying the non maxima suppression al...
void setNormalRadius(double normal_radius)
Set the radius used for the estimation of the surface normals of the input cloud.
void setThreshold32(double gamma_32)
Set the upper bound on the ratio between the third and the second eigenvalue.
bool initCompute() override
Perform the initial checks before computing the keypoints.
typename PointCloudN::Ptr PointCloudNPtr
void setNonMaxRadius(double non_max_radius)
Set the radius for the application of the non maxima suppression algorithm.
bool * getBoundaryPoints(PointCloudIn &input, double border_radius, float angle_threshold)
Compute the boundary points for the given input cloud.
void detectKeypoints(PointCloudOut &output) override
Detect the keypoints by performing the EVD of the scatter matrix.
typename Keypoint< PointInT, PointOutT >::PointCloudOut PointCloudOut
Surface normal estimation on organized data using integral images.
void setNormalEstimationMethod(NormalEstimationMethod normal_estimation_method)
Set the normal estimation method.
void setInputCloud(const typename PointCloudIn::ConstPtr &cloud) override
Provide a pointer to the input dataset (overwrites the PCLBase::setInputCloud method)
void setNormalSmoothingSize(float normal_smoothing_size)
Set the normal smoothing size.
Keypoint represents the base class for key points.
NormalEstimation estimates local surface properties (surface normals and curvatures)at each 3D point.
void setInputCloud(const PointCloudConstPtr &cloud) override
Provide a pointer to the input dataset.
virtual void setInputCloud(const PointCloudConstPtr &cloud)
Provide a pointer to the input dataset.
bool isFinite(const PointT &pt)
Tests if the 3D components of a point are all finite param[in] pt point to be tested return true if f...
IndicesAllocator<> Indices
Type used for indices in PCL.