123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- #ifndef FAST_GICP_FAST_GICP_IMPL_HPP
- #define FAST_GICP_FAST_GICP_IMPL_HPP
- #include <fast_gicp/so3/so3.hpp>
- namespace fast_gicp {
- template <typename PointSource, typename PointTarget>
- FastGICP<PointSource, PointTarget>::FastGICP() {
- #ifdef _OPENMP
- num_threads_ = omp_get_max_threads();
- #else
- num_threads_ = 1;
- #endif
- k_correspondences_ = 20;
- reg_name_ = "FastGICP";
- corr_dist_threshold_ = std::numeric_limits<float>::max();
- regularization_method_ = RegularizationMethod::PLANE;
- source_kdtree_.reset(new pcl::search::KdTree<PointSource>);
- target_kdtree_.reset(new pcl::search::KdTree<PointTarget>);
- }
- template <typename PointSource, typename PointTarget>
- FastGICP<PointSource, PointTarget>::~FastGICP() {}
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::setNumThreads(int n) {
- num_threads_ = n;
- #ifdef _OPENMP
- if (n == 0) {
- num_threads_ = omp_get_max_threads();
- }
- #endif
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::setCorrespondenceRandomness(int k) {
- k_correspondences_ = k;
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::setRegularizationMethod(RegularizationMethod method) {
- regularization_method_ = method;
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::swapSourceAndTarget() {
- input_.swap(target_);
- source_kdtree_.swap(target_kdtree_);
- source_covs_.swap(target_covs_);
- correspondences_.clear();
- sq_distances_.clear();
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::clearSource() {
- input_.reset();
- source_covs_.clear();
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::clearTarget() {
- target_.reset();
- target_covs_.clear();
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::setInputSource(const PointCloudSourceConstPtr& cloud) {
- if (input_ == cloud) {
- return;
- }
- pcl::Registration<PointSource, PointTarget, Scalar>::setInputSource(cloud);
- source_kdtree_->setInputCloud(cloud);
- source_covs_.clear();
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::setInputTarget(const PointCloudTargetConstPtr& cloud) {
- if (target_ == cloud) {
- return;
- }
- pcl::Registration<PointSource, PointTarget, Scalar>::setInputTarget(cloud);
- target_kdtree_->setInputCloud(cloud);
- target_covs_.clear();
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::setSourceCovariances(const std::vector<Eigen::Matrix4d, Eigen::aligned_allocator<Eigen::Matrix4d>>& covs) {
- source_covs_ = covs;
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::setTargetCovariances(const std::vector<Eigen::Matrix4d, Eigen::aligned_allocator<Eigen::Matrix4d>>& covs) {
- target_covs_ = covs;
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::computeTransformation(PointCloudSource& output, const Matrix4& guess) {
- if (source_covs_.size() != input_->size()) {
- calculate_covariances(input_, *source_kdtree_, source_covs_);
- }
- if (target_covs_.size() != target_->size()) {
- calculate_covariances(target_, *target_kdtree_, target_covs_);
- }
- LsqRegistration<PointSource, PointTarget>::computeTransformation(output, guess);
- }
- template <typename PointSource, typename PointTarget>
- void FastGICP<PointSource, PointTarget>::update_correspondences(const Eigen::Isometry3d& trans) {
- assert(source_covs_.size() == input_->size());
- assert(target_covs_.size() == target_->size());
- Eigen::Isometry3f trans_f = trans.cast<float>();
- correspondences_.resize(input_->size());
- sq_distances_.resize(input_->size());
- mahalanobis_.resize(input_->size());
- std::vector<int> k_indices(1);
- std::vector<float> k_sq_dists(1);
- #pragma omp parallel for num_threads(num_threads_) firstprivate(k_indices, k_sq_dists) schedule(guided, 8)
- for (int i = 0; i < input_->size(); i++) {
- PointTarget pt;
- pt.getVector4fMap() = trans_f * input_->at(i).getVector4fMap();
- target_kdtree_->nearestKSearch(pt, 1, k_indices, k_sq_dists);
- sq_distances_[i] = k_sq_dists[0];
- correspondences_[i] = k_sq_dists[0] < corr_dist_threshold_ * corr_dist_threshold_ ? k_indices[0] : -1;
- if (correspondences_[i] < 0) {
- continue;
- }
- const int target_index = correspondences_[i];
- const auto& cov_A = source_covs_[i];
- const auto& cov_B = target_covs_[target_index];
- Eigen::Matrix4d RCR = cov_B + trans.matrix() * cov_A * trans.matrix().transpose();
- RCR(3, 3) = 1.0;
- mahalanobis_[i] = RCR.inverse();
- mahalanobis_[i](3, 3) = 0.0f;
- }
- }
- template <typename PointSource, typename PointTarget>
- double FastGICP<PointSource, PointTarget>::linearize(const Eigen::Isometry3d& trans, Eigen::Matrix<double, 6, 6>* H, Eigen::Matrix<double, 6, 1>* b) {
- update_correspondences(trans);
- double sum_errors = 0.0;
- std::vector<Eigen::Matrix<double, 6, 6>, Eigen::aligned_allocator<Eigen::Matrix<double, 6, 6>>> Hs(num_threads_);
- std::vector<Eigen::Matrix<double, 6, 1>, Eigen::aligned_allocator<Eigen::Matrix<double, 6, 1>>> bs(num_threads_);
- for (int i = 0; i < num_threads_; i++) {
- Hs[i].setZero();
- bs[i].setZero();
- }
- #pragma omp parallel for num_threads(num_threads_) reduction(+ : sum_errors) schedule(guided, 8)
- for (int i = 0; i < input_->size(); i++) {
- int target_index = correspondences_[i];
- if (target_index < 0) {
- continue;
- }
- const Eigen::Vector4d mean_A = input_->at(i).getVector4fMap().template cast<double>();
- const auto& cov_A = source_covs_[i];
- const Eigen::Vector4d mean_B = target_->at(target_index).getVector4fMap().template cast<double>();
- const auto& cov_B = target_covs_[target_index];
- const Eigen::Vector4d transed_mean_A = trans * mean_A;
- const Eigen::Vector4d error = mean_B - transed_mean_A;
- sum_errors += error.transpose() * mahalanobis_[i] * error;
- if (H == nullptr || b == nullptr) {
- continue;
- }
- Eigen::Matrix<double, 4, 6> dtdx0 = Eigen::Matrix<double, 4, 6>::Zero();
- dtdx0.block<3, 3>(0, 0) = skewd(transed_mean_A.head<3>());
- dtdx0.block<3, 3>(0, 3) = -Eigen::Matrix3d::Identity();
- Eigen::Matrix<double, 4, 6> jlossexp = dtdx0;
- Eigen::Matrix<double, 6, 6> Hi = jlossexp.transpose() * mahalanobis_[i] * jlossexp;
- Eigen::Matrix<double, 6, 1> bi = jlossexp.transpose() * mahalanobis_[i] * error;
- Hs[omp_get_thread_num()] += Hi;
- bs[omp_get_thread_num()] += bi;
- }
- if (H && b) {
- H->setZero();
- b->setZero();
- for (int i = 0; i < num_threads_; i++) {
- (*H) += Hs[i];
- (*b) += bs[i];
- }
- }
- return sum_errors;
- }
- template <typename PointSource, typename PointTarget>
- double FastGICP<PointSource, PointTarget>::compute_error(const Eigen::Isometry3d& trans) {
- double sum_errors = 0.0;
- #pragma omp parallel for num_threads(num_threads_) reduction(+ : sum_errors) schedule(guided, 8)
- for (int i = 0; i < input_->size(); i++) {
- int target_index = correspondences_[i];
- if (target_index < 0) {
- continue;
- }
- const Eigen::Vector4d mean_A = input_->at(i).getVector4fMap().template cast<double>();
- const auto& cov_A = source_covs_[i];
- const Eigen::Vector4d mean_B = target_->at(target_index).getVector4fMap().template cast<double>();
- const auto& cov_B = target_covs_[target_index];
- const Eigen::Vector4d transed_mean_A = trans * mean_A;
- const Eigen::Vector4d error = mean_B - transed_mean_A;
- sum_errors += error.transpose() * mahalanobis_[i] * error;
- }
- return sum_errors;
- }
- template <typename PointSource, typename PointTarget>
- template <typename PointT>
- bool FastGICP<PointSource, PointTarget>::calculate_covariances(
- const typename pcl::PointCloud<PointT>::ConstPtr& cloud,
- pcl::search::KdTree<PointT>& kdtree,
- std::vector<Eigen::Matrix4d, Eigen::aligned_allocator<Eigen::Matrix4d>>& covariances) {
- if (kdtree.getInputCloud() != cloud) {
- kdtree.setInputCloud(cloud);
- }
- covariances.resize(cloud->size());
- #pragma omp parallel for num_threads(num_threads_) schedule(guided, 8)
- for (int i = 0; i < cloud->size(); i++) {
- std::vector<int> k_indices;
- std::vector<float> k_sq_distances;
- kdtree.nearestKSearch(cloud->at(i), k_correspondences_, k_indices, k_sq_distances);
- Eigen::Matrix<double, 4, -1> neighbors(4, k_correspondences_);
- for (int j = 0; j < k_indices.size(); j++) {
- neighbors.col(j) = cloud->at(k_indices[j]).getVector4fMap().template cast<double>();
- }
- neighbors.colwise() -= neighbors.rowwise().mean().eval();
- Eigen::Matrix4d cov = neighbors * neighbors.transpose() / k_correspondences_;
- if (regularization_method_ == RegularizationMethod::NONE) {
- covariances[i] = cov;
- } else if (regularization_method_ == RegularizationMethod::FROBENIUS) {
- double lambda = 1e-3;
- Eigen::Matrix3d C = cov.block<3, 3>(0, 0).cast<double>() + lambda * Eigen::Matrix3d::Identity();
- Eigen::Matrix3d C_inv = C.inverse();
- covariances[i].setZero();
- covariances[i].template block<3, 3>(0, 0) = (C_inv / C_inv.norm()).inverse();
- } else {
- Eigen::JacobiSVD<Eigen::Matrix3d> svd(cov.block<3, 3>(0, 0), Eigen::ComputeFullU | Eigen::ComputeFullV);
- Eigen::Vector3d values;
- switch (regularization_method_) {
- default:
- std::cerr << "here must not be reached" << std::endl;
- abort();
- case RegularizationMethod::PLANE:
- values = Eigen::Vector3d(1, 1, 1e-3);
- break;
- case RegularizationMethod::MIN_EIG:
- values = svd.singularValues().array().max(1e-3);
- break;
- case RegularizationMethod::NORMALIZED_MIN_EIG:
- values = svd.singularValues() / svd.singularValues().maxCoeff();
- values = values.array().max(1e-3);
- break;
- }
- covariances[i].setZero();
- covariances[i].template block<3, 3>(0, 0) = svd.matrixU() * values.asDiagonal() * svd.matrixV().transpose();
- }
- }
- return true;
- }
- } // namespace fast_gicp
- #endif
|