/* * Software License Agreement (BSD License) * * Point Cloud Library (PCL) - www.pointclouds.org * Copyright (c) 2009-2012, Willow Garage, Inc. * Copyright (c) 2012-, Open Perception, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the copyright holder(s) nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #pragma once // PCL includes #include namespace pcl { /** \brief @b JointIterativeClosestPoint extends ICP to multiple frames which * share the same transform. This is particularly useful when solving for * camera extrinsics using multiple observations. When given a single pair of * clouds, this reduces to vanilla ICP. * * \author Stephen Miller * \ingroup registration */ template class JointIterativeClosestPoint : public IterativeClosestPoint { public: using PointCloudSource = typename IterativeClosestPoint::PointCloudSource; using PointCloudSourcePtr = typename PointCloudSource::Ptr; using PointCloudSourceConstPtr = typename PointCloudSource::ConstPtr; using PointCloudTarget = typename IterativeClosestPoint::PointCloudTarget; using PointCloudTargetPtr = typename PointCloudTarget::Ptr; using PointCloudTargetConstPtr = typename PointCloudTarget::ConstPtr; using KdTree = pcl::search::KdTree; using KdTreePtr = typename KdTree::Ptr; using KdTreeReciprocal = pcl::search::KdTree; using KdTreeReciprocalPtr = typename KdTree::Ptr; using PointIndicesPtr = PointIndices::Ptr; using PointIndicesConstPtr = PointIndices::ConstPtr; using Ptr = shared_ptr>; using ConstPtr = shared_ptr>; using CorrespondenceEstimation = pcl::registration::CorrespondenceEstimationBase; using CorrespondenceEstimationPtr = typename CorrespondenceEstimation::Ptr; using CorrespondenceEstimationConstPtr = typename CorrespondenceEstimation::ConstPtr; using IterativeClosestPoint::reg_name_; using IterativeClosestPoint::getClassName; using IterativeClosestPoint::setInputSource; using IterativeClosestPoint::input_; using IterativeClosestPoint::indices_; using IterativeClosestPoint::target_; using IterativeClosestPoint::nr_iterations_; using IterativeClosestPoint::max_iterations_; using IterativeClosestPoint:: previous_transformation_; using IterativeClosestPoint::final_transformation_; using IterativeClosestPoint::transformation_; using IterativeClosestPoint:: transformation_epsilon_; using IterativeClosestPoint::converged_; using IterativeClosestPoint::corr_dist_threshold_; using IterativeClosestPoint::inlier_threshold_; using IterativeClosestPoint:: min_number_correspondences_; using IterativeClosestPoint::update_visualizer_; using IterativeClosestPoint:: euclidean_fitness_epsilon_; using IterativeClosestPoint::correspondences_; using IterativeClosestPoint:: transformation_estimation_; using IterativeClosestPoint:: correspondence_estimation_; using IterativeClosestPoint:: correspondence_rejectors_; using IterativeClosestPoint:: use_reciprocal_correspondence_; using IterativeClosestPoint::convergence_criteria_; using IterativeClosestPoint::source_has_normals_; using IterativeClosestPoint::target_has_normals_; using IterativeClosestPoint::need_source_blob_; using IterativeClosestPoint::need_target_blob_; using Matrix4 = typename IterativeClosestPoint::Matrix4; /** \brief Empty constructor. */ JointIterativeClosestPoint() { IterativeClosestPoint(); reg_name_ = "JointIterativeClosestPoint"; }; /** \brief Empty destructor */ ~JointIterativeClosestPoint() {} /** \brief Provide a pointer to the input source * (e.g., the point cloud that we want to align to the target) */ void setInputSource(const PointCloudSourceConstPtr& /*cloud*/) override { PCL_WARN("[pcl::%s::setInputSource] Warning; JointIterativeClosestPoint expects " "multiple clouds. Please use addInputSource.\n", getClassName().c_str()); return; } /** \brief Add a source cloud to the joint solver * * \param[in] cloud source cloud */ inline void addInputSource(const PointCloudSourceConstPtr& cloud) { // Set the parent InputSource, just to get all cached values (e.g. the existence of // normals). if (sources_.empty()) IterativeClosestPoint::setInputSource(cloud); sources_.push_back(cloud); } /** \brief Provide a pointer to the input target * (e.g., the point cloud that we want to align to the target) */ void setInputTarget(const PointCloudTargetConstPtr& /*cloud*/) override { PCL_WARN("[pcl::%s::setInputTarget] Warning; JointIterativeClosestPoint expects " "multiple clouds. Please use addInputTarget.\n", getClassName().c_str()); return; } /** \brief Add a target cloud to the joint solver * * \param[in] cloud target cloud */ inline void addInputTarget(const PointCloudTargetConstPtr& cloud) { // Set the parent InputTarget, just to get all cached values (e.g. the existence of // normals). if (targets_.empty()) IterativeClosestPoint::setInputTarget(cloud); targets_.push_back(cloud); } /** \brief Add a manual correspondence estimator * If you choose to do this, you must add one for each * input source / target pair. They do not need to have trees * or input clouds set ahead of time. * * \param[in] ce Correspondence estimation */ inline void addCorrespondenceEstimation(CorrespondenceEstimationPtr ce) { correspondence_estimations_.push_back(ce); } /** \brief Reset my list of input sources */ inline void clearInputSources() { sources_.clear(); } /** \brief Reset my list of input targets */ inline void clearInputTargets() { targets_.clear(); } /** \brief Reset my list of correspondence estimation methods. */ inline void clearCorrespondenceEstimations() { correspondence_estimations_.clear(); } protected: /** \brief Rigid transformation computation method with initial guess. * \param output the transformed input point cloud dataset using the rigid * transformation found \param guess the initial guess of the transformation to * compute */ void computeTransformation(PointCloudSource& output, const Matrix4& guess) override; /** \brief Looks at the Estimators and Rejectors and determines whether their * blob-setter methods need to be called */ void determineRequiredBlobData() override; std::vector sources_; std::vector targets_; std::vector correspondence_estimations_; }; } // namespace pcl #include