fast_vgicp_impl.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #ifndef FAST_GICP_FAST_VGICP_IMPL_HPP
  2. #define FAST_GICP_FAST_VGICP_IMPL_HPP
  3. #include <atomic>
  4. #include <Eigen/Core>
  5. #include <Eigen/Geometry>
  6. #include <pcl/point_types.h>
  7. #include <pcl/point_cloud.h>
  8. #include <pcl/search/kdtree.h>
  9. #include <pcl/registration/registration.h>
  10. #include <fast_gicp/so3/so3.hpp>
  11. #include <fast_gicp/gicp/fast_vgicp.hpp>
  12. namespace fast_gicp {
  13. template <typename PointSource, typename PointTarget>
  14. FastVGICP<PointSource, PointTarget>::FastVGICP() : FastGICP<PointSource, PointTarget>() {
  15. this->reg_name_ = "FastVGICP";
  16. voxel_resolution_ = 1.0;
  17. search_method_ = NeighborSearchMethod::DIRECT1;
  18. voxel_mode_ = VoxelAccumulationMode::ADDITIVE;
  19. }
  20. template <typename PointSource, typename PointTarget>
  21. FastVGICP<PointSource, PointTarget>::~FastVGICP() {}
  22. template <typename PointSource, typename PointTarget>
  23. void FastVGICP<PointSource, PointTarget>::setResolution(double resolution) {
  24. voxel_resolution_ = resolution;
  25. }
  26. template <typename PointSource, typename PointTarget>
  27. void FastVGICP<PointSource, PointTarget>::setNeighborSearchMethod(NeighborSearchMethod method) {
  28. search_method_ = method;
  29. }
  30. template <typename PointSource, typename PointTarget>
  31. void FastVGICP<PointSource, PointTarget>::setVoxelAccumulationMode(VoxelAccumulationMode mode) {
  32. voxel_mode_ = mode;
  33. }
  34. template <typename PointSource, typename PointTarget>
  35. void FastVGICP<PointSource, PointTarget>::swapSourceAndTarget() {
  36. input_.swap(target_);
  37. source_kdtree_.swap(target_kdtree_);
  38. source_covs_.swap(target_covs_);
  39. voxelmap_.reset();
  40. voxel_correspondences_.clear();
  41. voxel_mahalanobis_.clear();
  42. }
  43. template <typename PointSource, typename PointTarget>
  44. void FastVGICP<PointSource, PointTarget>::setInputTarget(const PointCloudTargetConstPtr& cloud) {
  45. if (target_ == cloud) {
  46. return;
  47. }
  48. FastGICP<PointSource, PointTarget>::setInputTarget(cloud);
  49. voxelmap_.reset();
  50. }
  51. template <typename PointSource, typename PointTarget>
  52. void FastVGICP<PointSource, PointTarget>::computeTransformation(PointCloudSource& output, const Matrix4& guess) {
  53. voxelmap_.reset();
  54. FastGICP<PointSource, PointTarget>::computeTransformation(output, guess);
  55. }
  56. template <typename PointSource, typename PointTarget>
  57. void FastVGICP<PointSource, PointTarget>::update_correspondences(const Eigen::Isometry3d& trans) {
  58. voxel_correspondences_.clear();
  59. auto offsets = neighbor_offsets(search_method_);
  60. std::vector<std::vector<std::pair<int, GaussianVoxel::Ptr>>> corrs(num_threads_);
  61. for (auto& c : corrs) {
  62. c.reserve((input_->size() * offsets.size()) / num_threads_);
  63. }
  64. #pragma omp parallel for num_threads(num_threads_) schedule(guided, 8)
  65. for (int i = 0; i < input_->size(); i++) {
  66. const Eigen::Vector4d mean_A = input_->at(i).getVector4fMap().template cast<double>();
  67. Eigen::Vector4d transed_mean_A = trans * mean_A;
  68. Eigen::Vector3i coord = voxelmap_->voxel_coord(transed_mean_A);
  69. for (const auto& offset : offsets) {
  70. auto voxel = voxelmap_->lookup_voxel(coord + offset);
  71. if (voxel != nullptr) {
  72. corrs[omp_get_thread_num()].push_back(std::make_pair(i, voxel));
  73. }
  74. }
  75. }
  76. voxel_correspondences_.reserve(input_->size() * offsets.size());
  77. for (const auto& c : corrs) {
  78. voxel_correspondences_.insert(voxel_correspondences_.end(), c.begin(), c.end());
  79. }
  80. // precompute combined covariances
  81. voxel_mahalanobis_.resize(voxel_correspondences_.size());
  82. #pragma omp parallel for num_threads(num_threads_) schedule(guided, 8)
  83. for (int i = 0; i < voxel_correspondences_.size(); i++) {
  84. const auto& corr = voxel_correspondences_[i];
  85. const auto& cov_A = source_covs_[corr.first];
  86. const auto& cov_B = corr.second->cov;
  87. Eigen::Matrix4d RCR = cov_B + trans.matrix() * cov_A * trans.matrix().transpose();
  88. RCR(3, 3) = 1.0;
  89. voxel_mahalanobis_[i] = RCR.inverse();
  90. voxel_mahalanobis_[i](3, 3) = 0.0;
  91. }
  92. }
  93. template <typename PointSource, typename PointTarget>
  94. double FastVGICP<PointSource, PointTarget>::linearize(const Eigen::Isometry3d& trans, Eigen::Matrix<double, 6, 6>* H, Eigen::Matrix<double, 6, 1>* b) {
  95. if (voxelmap_ == nullptr) {
  96. voxelmap_.reset(new GaussianVoxelMap<PointTarget>(voxel_resolution_, voxel_mode_));
  97. voxelmap_->create_voxelmap(*target_, target_covs_);
  98. }
  99. update_correspondences(trans);
  100. double sum_errors = 0.0;
  101. std::vector<Eigen::Matrix<double, 6, 6>, Eigen::aligned_allocator<Eigen::Matrix<double, 6, 6>>> Hs(num_threads_);
  102. std::vector<Eigen::Matrix<double, 6, 1>, Eigen::aligned_allocator<Eigen::Matrix<double, 6, 1>>> bs(num_threads_);
  103. for (int i = 0; i < num_threads_; i++) {
  104. Hs[i].setZero();
  105. bs[i].setZero();
  106. }
  107. #pragma omp parallel for num_threads(num_threads_) reduction(+ : sum_errors) schedule(guided, 8)
  108. for (int i = 0; i < voxel_correspondences_.size(); i++) {
  109. const auto& corr = voxel_correspondences_[i];
  110. auto target_voxel = corr.second;
  111. const Eigen::Vector4d mean_A = input_->at(corr.first).getVector4fMap().template cast<double>();
  112. const auto& cov_A = source_covs_[corr.first];
  113. const Eigen::Vector4d mean_B = corr.second->mean;
  114. const auto& cov_B = corr.second->cov;
  115. const Eigen::Vector4d transed_mean_A = trans * mean_A;
  116. const Eigen::Vector4d error = mean_B - transed_mean_A;
  117. double w = std::sqrt(target_voxel->num_points);
  118. sum_errors += w * error.transpose() * voxel_mahalanobis_[i] * error;
  119. if (H == nullptr || b == nullptr) {
  120. continue;
  121. }
  122. Eigen::Matrix<double, 4, 6> dtdx0 = Eigen::Matrix<double, 4, 6>::Zero();
  123. dtdx0.block<3, 3>(0, 0) = skewd(transed_mean_A.head<3>());
  124. dtdx0.block<3, 3>(0, 3) = -Eigen::Matrix3d::Identity();
  125. Eigen::Matrix<double, 4, 6> jlossexp = dtdx0;
  126. Eigen::Matrix<double, 6, 6> Hi = w * jlossexp.transpose() * voxel_mahalanobis_[i] * jlossexp;
  127. Eigen::Matrix<double, 6, 1> bi = w * jlossexp.transpose() * voxel_mahalanobis_[i] * error;
  128. int thread_num = omp_get_thread_num();
  129. Hs[thread_num] += Hi;
  130. bs[thread_num] += bi;
  131. }
  132. if (H && b) {
  133. H->setZero();
  134. b->setZero();
  135. for (int i = 0; i < num_threads_; i++) {
  136. (*H) += Hs[i];
  137. (*b) += bs[i];
  138. }
  139. }
  140. return sum_errors;
  141. }
  142. template <typename PointSource, typename PointTarget>
  143. double FastVGICP<PointSource, PointTarget>::compute_error(const Eigen::Isometry3d& trans) {
  144. double sum_errors = 0.0;
  145. #pragma omp parallel for num_threads(num_threads_) reduction(+ : sum_errors)
  146. for (int i = 0; i < voxel_correspondences_.size(); i++) {
  147. const auto& corr = voxel_correspondences_[i];
  148. auto target_voxel = corr.second;
  149. const Eigen::Vector4d mean_A = input_->at(corr.first).getVector4fMap().template cast<double>();
  150. const auto& cov_A = source_covs_[corr.first];
  151. const Eigen::Vector4d mean_B = corr.second->mean;
  152. const auto& cov_B = corr.second->cov;
  153. const Eigen::Vector4d transed_mean_A = trans * mean_A;
  154. const Eigen::Vector4d error = mean_B - transed_mean_A;
  155. double w = std::sqrt(target_voxel->num_points);
  156. sum_errors += w * error.transpose() * voxel_mahalanobis_[i] * error;
  157. }
  158. return sum_errors;
  159. }
  160. } // namespace fast_gicp
  161. #endif