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 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> solver (cov_m);
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...
void getCoordinateSystemOnPlane(const PointNT &p_coeff, Eigen::Vector4f &u, Eigen::Vector4f &v)
Get a u-v-n coordinate system that lies on a plane defined by its normal.
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)
Check whether a point is a boundary point in a planar patch of projected points given by indices.
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.