voxel_grid_covariance_omp.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /*
  2. * Software License Agreement (BSD License)
  3. *
  4. * Point Cloud Library (PCL) - www.pointclouds.org
  5. * Copyright (c) 2010-2011, Willow Garage, Inc.
  6. *
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. *
  13. * * Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. * * Redistributions in binary form must reproduce the above
  16. * copyright notice, this list of conditions and the following
  17. * disclaimer in the documentation and/or other materials provided
  18. * with the distribution.
  19. * * Neither the name of the copyright holder(s) nor the names of its
  20. * contributors may be used to endorse or promote products derived
  21. * from this software without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  26. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  27. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  28. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  29. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  30. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  31. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  33. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. * POSSIBILITY OF SUCH DAMAGE.
  35. *
  36. */
  37. #ifndef PCL_VOXEL_GRID_COVARIANCE_OMP_H_
  38. #define PCL_VOXEL_GRID_COVARIANCE_OMP_H_
  39. #include <pcl/pcl_macros.h>
  40. #include <pcl/filters/boost.h>
  41. #include <pcl/filters/voxel_grid.h>
  42. #include <map>
  43. #include <unordered_map>
  44. #include <pcl/point_types.h>
  45. #include <pcl/kdtree/kdtree_flann.h>
  46. namespace pclomp
  47. {
  48. /** \brief A searchable voxel structure containing the mean and covariance of the data.
  49. * \note For more information please see
  50. * <b>Magnusson, M. (2009). The Three-Dimensional Normal-Distributions Transform —
  51. * an Efficient Representation for Registration, Surface Analysis, and Loop Detection.
  52. * PhD thesis, Orebro University. Orebro Studies in Technology 36</b>
  53. * \author Brian Okorn (Space and Naval Warfare Systems Center Pacific)
  54. */
  55. template<typename PointT>
  56. class VoxelGridCovariance : public pcl::VoxelGrid<PointT>
  57. {
  58. protected:
  59. using pcl::VoxelGrid<PointT>::filter_name_;
  60. using pcl::VoxelGrid<PointT>::getClassName;
  61. using pcl::VoxelGrid<PointT>::input_;
  62. using pcl::VoxelGrid<PointT>::indices_;
  63. using pcl::VoxelGrid<PointT>::filter_limit_negative_;
  64. using pcl::VoxelGrid<PointT>::filter_limit_min_;
  65. using pcl::VoxelGrid<PointT>::filter_limit_max_;
  66. using pcl::VoxelGrid<PointT>::filter_field_name_;
  67. using pcl::VoxelGrid<PointT>::downsample_all_data_;
  68. using pcl::VoxelGrid<PointT>::leaf_layout_;
  69. using pcl::VoxelGrid<PointT>::save_leaf_layout_;
  70. using pcl::VoxelGrid<PointT>::leaf_size_;
  71. using pcl::VoxelGrid<PointT>::min_b_;
  72. using pcl::VoxelGrid<PointT>::max_b_;
  73. using pcl::VoxelGrid<PointT>::inverse_leaf_size_;
  74. using pcl::VoxelGrid<PointT>::div_b_;
  75. using pcl::VoxelGrid<PointT>::divb_mul_;
  76. typedef typename pcl::traits::fieldList<PointT>::type FieldList;
  77. typedef typename pcl::Filter<PointT>::PointCloud PointCloud;
  78. typedef typename PointCloud::Ptr PointCloudPtr;
  79. typedef typename PointCloud::ConstPtr PointCloudConstPtr;
  80. public:
  81. #if PCL_VERSION >= PCL_VERSION_CALC(1, 10, 0)
  82. typedef pcl::shared_ptr< pcl::VoxelGrid<PointT> > Ptr;
  83. typedef pcl::shared_ptr< const pcl::VoxelGrid<PointT> > ConstPtr;
  84. #else
  85. typedef boost::shared_ptr< pcl::VoxelGrid<PointT> > Ptr;
  86. typedef boost::shared_ptr< const pcl::VoxelGrid<PointT> > ConstPtr;
  87. #endif
  88. /** \brief Simple structure to hold a centroid, covariance and the number of points in a leaf.
  89. * Inverse covariance, eigen vectors and eigen values are precomputed. */
  90. struct Leaf
  91. {
  92. /** \brief Constructor.
  93. * Sets \ref nr_points, \ref icov_, \ref mean_ and \ref evals_ to 0 and \ref cov_ and \ref evecs_ to the identity matrix
  94. */
  95. Leaf () :
  96. nr_points (0),
  97. mean_ (Eigen::Vector3d::Zero ()),
  98. centroid (),
  99. cov_ (Eigen::Matrix3d::Identity ()),
  100. icov_ (Eigen::Matrix3d::Zero ()),
  101. evecs_ (Eigen::Matrix3d::Identity ()),
  102. evals_ (Eigen::Vector3d::Zero ())
  103. {
  104. }
  105. /** \brief Get the voxel covariance.
  106. * \return covariance matrix
  107. */
  108. Eigen::Matrix3d
  109. getCov () const
  110. {
  111. return (cov_);
  112. }
  113. /** \brief Get the inverse of the voxel covariance.
  114. * \return inverse covariance matrix
  115. */
  116. Eigen::Matrix3d
  117. getInverseCov () const
  118. {
  119. return (icov_);
  120. }
  121. /** \brief Get the voxel centroid.
  122. * \return centroid
  123. */
  124. Eigen::Vector3d
  125. getMean () const
  126. {
  127. return (mean_);
  128. }
  129. /** \brief Get the eigen vectors of the voxel covariance.
  130. * \note Order corresponds with \ref getEvals
  131. * \return matrix whose columns contain eigen vectors
  132. */
  133. Eigen::Matrix3d
  134. getEvecs () const
  135. {
  136. return (evecs_);
  137. }
  138. /** \brief Get the eigen values of the voxel covariance.
  139. * \note Order corresponds with \ref getEvecs
  140. * \return vector of eigen values
  141. */
  142. Eigen::Vector3d
  143. getEvals () const
  144. {
  145. return (evals_);
  146. }
  147. /** \brief Get the number of points contained by this voxel.
  148. * \return number of points
  149. */
  150. int
  151. getPointCount () const
  152. {
  153. return (nr_points);
  154. }
  155. /** \brief Number of points contained by voxel */
  156. int nr_points;
  157. /** \brief 3D voxel centroid */
  158. Eigen::Vector3d mean_;
  159. /** \brief Nd voxel centroid
  160. * \note Differs from \ref mean_ when color data is used
  161. */
  162. Eigen::VectorXf centroid;
  163. /** \brief Voxel covariance matrix */
  164. Eigen::Matrix3d cov_;
  165. /** \brief Inverse of voxel covariance matrix */
  166. Eigen::Matrix3d icov_;
  167. /** \brief Eigen vectors of voxel covariance matrix */
  168. Eigen::Matrix3d evecs_;
  169. /** \brief Eigen values of voxel covariance matrix */
  170. Eigen::Vector3d evals_;
  171. };
  172. /** \brief Pointer to VoxelGridCovariance leaf structure */
  173. typedef Leaf* LeafPtr;
  174. /** \brief Const pointer to VoxelGridCovariance leaf structure */
  175. typedef const Leaf* LeafConstPtr;
  176. typedef std::map<size_t, Leaf> Map;
  177. public:
  178. /** \brief Constructor.
  179. * Sets \ref leaf_size_ to 0 and \ref searchable_ to false.
  180. */
  181. VoxelGridCovariance () :
  182. searchable_ (true),
  183. min_points_per_voxel_ (6),
  184. min_covar_eigvalue_mult_ (0.01),
  185. leaves_ (),
  186. voxel_centroids_ (),
  187. voxel_centroids_leaf_indices_ (),
  188. kdtree_ ()
  189. {
  190. downsample_all_data_ = false;
  191. save_leaf_layout_ = false;
  192. leaf_size_.setZero ();
  193. min_b_.setZero ();
  194. max_b_.setZero ();
  195. filter_name_ = "VoxelGridCovariance";
  196. }
  197. /** \brief Set the minimum number of points required for a cell to be used (must be 3 or greater for covariance calculation).
  198. * \param[in] min_points_per_voxel the minimum number of points for required for a voxel to be used
  199. */
  200. inline void
  201. setMinPointPerVoxel (int min_points_per_voxel)
  202. {
  203. if(min_points_per_voxel > 2)
  204. {
  205. min_points_per_voxel_ = min_points_per_voxel;
  206. }
  207. else
  208. {
  209. PCL_WARN ("%s: Covariance calculation requires at least 3 points, setting Min Point per Voxel to 3 ", this->getClassName ().c_str ());
  210. min_points_per_voxel_ = 3;
  211. }
  212. }
  213. /** \brief Get the minimum number of points required for a cell to be used.
  214. * \return the minimum number of points for required for a voxel to be used
  215. */
  216. inline int
  217. getMinPointPerVoxel ()
  218. {
  219. return min_points_per_voxel_;
  220. }
  221. /** \brief Set the minimum allowable ratio between eigenvalues to prevent singular covariance matrices.
  222. * \param[in] min_covar_eigvalue_mult the minimum allowable ratio between eigenvalues
  223. */
  224. inline void
  225. setCovEigValueInflationRatio (double min_covar_eigvalue_mult)
  226. {
  227. min_covar_eigvalue_mult_ = min_covar_eigvalue_mult;
  228. }
  229. /** \brief Get the minimum allowable ratio between eigenvalues to prevent singular covariance matrices.
  230. * \return the minimum allowable ratio between eigenvalues
  231. */
  232. inline double
  233. getCovEigValueInflationRatio ()
  234. {
  235. return min_covar_eigvalue_mult_;
  236. }
  237. /** \brief Filter cloud and initializes voxel structure.
  238. * \param[out] output cloud containing centroids of voxels containing a sufficient number of points
  239. * \param[in] searchable flag if voxel structure is searchable, if true then kdtree is built
  240. */
  241. inline void
  242. filter (PointCloud &output, bool searchable = false)
  243. {
  244. searchable_ = searchable;
  245. applyFilter (output);
  246. voxel_centroids_ = PointCloudPtr (new PointCloud (output));
  247. if (searchable_ && voxel_centroids_->size() > 0)
  248. {
  249. // Initiates kdtree of the centroids of voxels containing a sufficient number of points
  250. kdtree_.setInputCloud (voxel_centroids_);
  251. }
  252. }
  253. /** \brief Initializes voxel structure.
  254. * \param[in] searchable flag if voxel structure is searchable, if true then kdtree is built
  255. */
  256. inline void
  257. filter (bool searchable = false)
  258. {
  259. searchable_ = searchable;
  260. voxel_centroids_ = PointCloudPtr (new PointCloud);
  261. applyFilter (*voxel_centroids_);
  262. if (searchable_ && voxel_centroids_->size() > 0)
  263. {
  264. // Initiates kdtree of the centroids of voxels containing a sufficient number of points
  265. kdtree_.setInputCloud (voxel_centroids_);
  266. }
  267. }
  268. /** \brief Get the voxel containing point p.
  269. * \param[in] index the index of the leaf structure node
  270. * \return const pointer to leaf structure
  271. */
  272. inline LeafConstPtr
  273. getLeaf (int index)
  274. {
  275. auto leaf_iter = leaves_.find (index);
  276. if (leaf_iter != leaves_.end ())
  277. {
  278. LeafConstPtr ret (&(leaf_iter->second));
  279. return ret;
  280. }
  281. else
  282. return NULL;
  283. }
  284. /** \brief Get the voxel containing point p.
  285. * \param[in] p the point to get the leaf structure at
  286. * \return const pointer to leaf structure
  287. */
  288. inline LeafConstPtr
  289. getLeaf (PointT &p)
  290. {
  291. // Generate index associated with p
  292. int ijk0 = static_cast<int> (floor (p.x * inverse_leaf_size_[0]) - min_b_[0]);
  293. int ijk1 = static_cast<int> (floor (p.y * inverse_leaf_size_[1]) - min_b_[1]);
  294. int ijk2 = static_cast<int> (floor (p.z * inverse_leaf_size_[2]) - min_b_[2]);
  295. // Compute the centroid leaf index
  296. int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
  297. // Find leaf associated with index
  298. auto leaf_iter = leaves_.find (idx);
  299. if (leaf_iter != leaves_.end ())
  300. {
  301. // If such a leaf exists return the pointer to the leaf structure
  302. LeafConstPtr ret (&(leaf_iter->second));
  303. return ret;
  304. }
  305. else
  306. return NULL;
  307. }
  308. /** \brief Get the voxel containing point p.
  309. * \param[in] p the point to get the leaf structure at
  310. * \return const pointer to leaf structure
  311. */
  312. inline LeafConstPtr
  313. getLeaf (Eigen::Vector3f &p)
  314. {
  315. // Generate index associated with p
  316. int ijk0 = static_cast<int> (floor (p[0] * inverse_leaf_size_[0]) - min_b_[0]);
  317. int ijk1 = static_cast<int> (floor (p[1] * inverse_leaf_size_[1]) - min_b_[1]);
  318. int ijk2 = static_cast<int> (floor (p[2] * inverse_leaf_size_[2]) - min_b_[2]);
  319. // Compute the centroid leaf index
  320. int idx = ijk0 * divb_mul_[0] + ijk1 * divb_mul_[1] + ijk2 * divb_mul_[2];
  321. // Find leaf associated with index
  322. auto leaf_iter = leaves_.find (idx);
  323. if (leaf_iter != leaves_.end ())
  324. {
  325. // If such a leaf exists return the pointer to the leaf structure
  326. LeafConstPtr ret (&(leaf_iter->second));
  327. return ret;
  328. }
  329. else
  330. return NULL;
  331. }
  332. /** \brief Get the voxels surrounding point p, not including the voxel containing point p.
  333. * \note Only voxels containing a sufficient number of points are used (slower than radius search in practice).
  334. * \param[in] reference_point the point to get the leaf structure at
  335. * \param[out] neighbors
  336. * \return number of neighbors found
  337. */
  338. int getNeighborhoodAtPoint(const Eigen::MatrixXi&, const PointT& reference_point, std::vector<LeafConstPtr> &neighbors) const ;
  339. int getNeighborhoodAtPoint(const PointT& reference_point, std::vector<LeafConstPtr> &neighbors) const ;
  340. int getNeighborhoodAtPoint7(const PointT& reference_point, std::vector<LeafConstPtr> &neighbors) const ;
  341. int getNeighborhoodAtPoint1(const PointT& reference_point, std::vector<LeafConstPtr> &neighbors) const ;
  342. /** \brief Get the leaf structure map
  343. * \return a map containing all leaves
  344. */
  345. inline const Map&
  346. getLeaves ()
  347. {
  348. return leaves_;
  349. }
  350. /** \brief Get a pointcloud containing the voxel centroids
  351. * \note Only voxels containing a sufficient number of points are used.
  352. * \return a map containing all leaves
  353. */
  354. inline PointCloudPtr
  355. getCentroids ()
  356. {
  357. return voxel_centroids_;
  358. }
  359. /** \brief Get a cloud to visualize each voxels normal distribution.
  360. * \param[out] cell_cloud a cloud created by sampling the normal distributions of each voxel
  361. */
  362. void
  363. getDisplayCloud (pcl::PointCloud<pcl::PointXYZ>& cell_cloud);
  364. /** \brief Search for the k-nearest occupied voxels for the given query point.
  365. * \note Only voxels containing a sufficient number of points are used.
  366. * \param[in] point the given query point
  367. * \param[in] k the number of neighbors to search for
  368. * \param[out] k_leaves the resultant leaves of the neighboring points
  369. * \param[out] k_sqr_distances the resultant squared distances to the neighboring points
  370. * \return number of neighbors found
  371. */
  372. int
  373. nearestKSearch (const PointT &point, int k,
  374. std::vector<LeafConstPtr> &k_leaves, std::vector<float> &k_sqr_distances)
  375. {
  376. k_leaves.clear ();
  377. // Check if kdtree has been built
  378. if (!searchable_)
  379. {
  380. PCL_WARN ("%s: Not Searchable", this->getClassName ().c_str ());
  381. return 0;
  382. }
  383. // Find k-nearest neighbors in the occupied voxel centroid cloud
  384. std::vector<int> k_indices;
  385. k = kdtree_.nearestKSearch (point, k, k_indices, k_sqr_distances);
  386. // Find leaves corresponding to neighbors
  387. k_leaves.reserve (k);
  388. for (std::vector<int>::iterator iter = k_indices.begin (); iter != k_indices.end (); iter++)
  389. {
  390. k_leaves.push_back (&leaves_[voxel_centroids_leaf_indices_[*iter]]);
  391. }
  392. return k;
  393. }
  394. /** \brief Search for the k-nearest occupied voxels for the given query point.
  395. * \note Only voxels containing a sufficient number of points are used.
  396. * \param[in] cloud the given query point
  397. * \param[in] index the index
  398. * \param[in] k the number of neighbors to search for
  399. * \param[out] k_leaves the resultant leaves of the neighboring points
  400. * \param[out] k_sqr_distances the resultant squared distances to the neighboring points
  401. * \return number of neighbors found
  402. */
  403. inline int
  404. nearestKSearch (const PointCloud &cloud, int index, int k,
  405. std::vector<LeafConstPtr> &k_leaves, std::vector<float> &k_sqr_distances)
  406. {
  407. if (index >= static_cast<int> (cloud.points.size ()) || index < 0)
  408. return (0);
  409. return (nearestKSearch (cloud.points[index], k, k_leaves, k_sqr_distances));
  410. }
  411. /** \brief Search for all the nearest occupied voxels of the query point in a given radius.
  412. * \note Only voxels containing a sufficient number of points are used.
  413. * \param[in] point the given query point
  414. * \param[in] radius the radius of the sphere bounding all of p_q's neighbors
  415. * \param[out] k_leaves the resultant leaves of the neighboring points
  416. * \param[out] k_sqr_distances the resultant squared distances to the neighboring points
  417. * \param[in] max_nn
  418. * \return number of neighbors found
  419. */
  420. int
  421. radiusSearch (const PointT &point, double radius, std::vector<LeafConstPtr> &k_leaves,
  422. std::vector<float> &k_sqr_distances, unsigned int max_nn = 0) const
  423. {
  424. k_leaves.clear ();
  425. // Check if kdtree has been built
  426. if (!searchable_)
  427. {
  428. PCL_WARN ("%s: Not Searchable", this->getClassName ().c_str ());
  429. return 0;
  430. }
  431. // Find neighbors within radius in the occupied voxel centroid cloud
  432. std::vector<int> k_indices;
  433. int k = kdtree_.radiusSearch (point, radius, k_indices, k_sqr_distances, max_nn);
  434. // Find leaves corresponding to neighbors
  435. k_leaves.reserve (k);
  436. for (std::vector<int>::iterator iter = k_indices.begin (); iter != k_indices.end (); iter++)
  437. {
  438. auto leaf = leaves_.find(voxel_centroids_leaf_indices_[*iter]);
  439. if (leaf == leaves_.end()) {
  440. std::cerr << "error : could not find the leaf corresponding to the voxel" << std::endl;
  441. std::cin.ignore(1);
  442. }
  443. k_leaves.push_back (&(leaf->second));
  444. }
  445. return k;
  446. }
  447. /** \brief Search for all the nearest occupied voxels of the query point in a given radius.
  448. * \note Only voxels containing a sufficient number of points are used.
  449. * \param[in] cloud the given query point
  450. * \param[in] index a valid index in cloud representing a valid (i.e., finite) query point
  451. * \param[in] radius the radius of the sphere bounding all of p_q's neighbors
  452. * \param[out] k_leaves the resultant leaves of the neighboring points
  453. * \param[out] k_sqr_distances the resultant squared distances to the neighboring points
  454. * \param[in] max_nn
  455. * \return number of neighbors found
  456. */
  457. inline int
  458. radiusSearch (const PointCloud &cloud, int index, double radius,
  459. std::vector<LeafConstPtr> &k_leaves, std::vector<float> &k_sqr_distances,
  460. unsigned int max_nn = 0) const
  461. {
  462. if (index >= static_cast<int> (cloud.points.size ()) || index < 0)
  463. return (0);
  464. return (radiusSearch (cloud.points[index], radius, k_leaves, k_sqr_distances, max_nn));
  465. }
  466. protected:
  467. /** \brief Filter cloud and initializes voxel structure.
  468. * \param[out] output cloud containing centroids of voxels containing a sufficient number of points
  469. */
  470. void applyFilter (PointCloud &output);
  471. /** \brief Flag to determine if voxel structure is searchable. */
  472. bool searchable_;
  473. /** \brief Minimum points contained with in a voxel to allow it to be usable. */
  474. int min_points_per_voxel_;
  475. /** \brief Minimum allowable ratio between eigenvalues to prevent singular covariance matrices. */
  476. double min_covar_eigvalue_mult_;
  477. /** \brief Voxel structure containing all leaf nodes (includes voxels with less than a sufficient number of points). */
  478. Map leaves_;
  479. /** \brief Point cloud containing centroids of voxels containing at least minimum number of points. */
  480. PointCloudPtr voxel_centroids_;
  481. /** \brief Indices of leaf structures associated with each point in \ref voxel_centroids_ (used for searching). */
  482. std::vector<int> voxel_centroids_leaf_indices_;
  483. /** \brief KdTree generated using \ref voxel_centroids_ (used for searching). */
  484. pcl::KdTreeFLANN<PointT> kdtree_;
  485. };
  486. }
  487. #endif //#ifndef PCL_VOXEL_GRID_COVARIANCE_H_