/* * Software License Agreement (BSD License) * * Point Cloud Library (PCL) - www.pointclouds.org * Copyright (c) 2014-, 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 // common includes #include #include #include // segmentation and sample consensus includes #include #include #include #include #define PCL_INSTANTIATE_CPCSegmentation(T) template class PCL_EXPORTS pcl::CPCSegmentation; namespace pcl { /** \brief A segmentation algorithm partitioning a supervoxel graph. It uses planar cuts induced by local concavities for the recursive segmentation. Cuts are estimated using locally constrained directed RANSAC. * \note If you use this in a scientific work please cite the following paper: * M. Schoeler, J. Papon, F. Woergoetter * Constrained Planar Cuts - Object Partitioning for Point Clouds * In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR) 2015 * Inherits most of its functionality from \ref LCCPSegmentation * \author Markus Schoeler (mschoeler@web.de) * \ingroup segmentation */ template class CPCSegmentation : public LCCPSegmentation { using WeightSACPointType = PointXYZINormal; using LCCP = LCCPSegmentation; // LCCP typedefs using EdgeID = typename LCCP::EdgeID; using EdgeIterator = typename LCCP::EdgeIterator; // LCCP methods using LCCP::calculateConvexConnections; using LCCP::applyKconvexity; using LCCP::doGrouping; using LCCP::mergeSmallSegments; // LCCP variables using LCCP::sv_adjacency_list_; using LCCP::k_factor_; using LCCP::grouping_data_valid_; using LCCP::sv_label_to_seg_label_map_; using LCCP::sv_label_to_supervoxel_map_; using LCCP::concavity_tolerance_threshold_; using LCCP::seed_resolution_; using LCCP::supervoxels_set_; public: CPCSegmentation (); ~CPCSegmentation (); /** \brief Merge supervoxels using cuts through local convexities. The input parameters are generated by using the \ref SupervoxelClustering class. To retrieve the output use the \ref relabelCloud method. * \note There are three ways to retrieve the segmentation afterwards (inherited from \ref LCCPSegmentation): \ref relabelCloud, \ref getSupervoxelToSegmentMap and \ref getSupervoxelToSegmentMap */ void segment (); /** \brief Determines if we want to use cutting planes * \param[in] max_cuts Maximum number of cuts * \param[in] cutting_min_segments Minimum segment size for cutting * \param[in] cutting_min_score Minimum score a proposed cut has to achieve for being performed * \param[in] locally_constrained Decide if we constrain our cuts locally * \param[in] directed_cutting Decide if we prefer cuts perpendicular to the edge-direction * \param[in] clean_cutting Decide if we cut only edges with supervoxels on opposite sides of the plane (clean) or all edges within the seed_resolution_ distance to the plane (not clean). The later was used in the paper. */ inline void setCutting (const std::uint32_t max_cuts = 20, const std::uint32_t cutting_min_segments = 0, const float cutting_min_score = 0.16, const bool locally_constrained = true, const bool directed_cutting = true, const bool clean_cutting = false) { max_cuts_ = max_cuts; min_segment_size_for_cutting_ = cutting_min_segments; min_cut_score_ = cutting_min_score; use_local_constrains_ = locally_constrained; use_directed_weights_ = directed_cutting; use_clean_cutting_ = clean_cutting; } /** \brief Set the number of iterations for the weighted RANSAC step (best cut estimations) * \param[in] ransac_iterations The number of iterations */ inline void setRANSACIterations (const std::uint32_t ransac_iterations) { ransac_itrs_ = ransac_iterations; } private: /** \brief Used in for CPC to find and fit cutting planes to the pointcloud. * \note Is used recursively * \param[in] depth_levels_left When first calling the function set this parameter to the maximum levels you want to cut down */ void applyCuttingPlane (std::uint32_t depth_levels_left); /// *** Parameters *** /// /** \brief Maximum number of cuts */ std::uint32_t max_cuts_; /** \brief Minimum segment size for cutting */ std::uint32_t min_segment_size_for_cutting_; /** \brief Cut_score threshold */ float min_cut_score_; /** \brief Use local constrains for cutting */ bool use_local_constrains_; /** \brief Use directed weights for the cutting */ bool use_directed_weights_; /** \brief Use clean cutting */ bool use_clean_cutting_; /** \brief Iterations for RANSAC */ std::uint32_t ransac_itrs_; /******************************************* Directional weighted RANSAC declarations ******************************************************************/ /** \brief @b WeightedRandomSampleConsensus represents an implementation of the Directionally Weighted RANSAC algorithm, as described in: "Constrained Planar Cuts - Part Segmentation for Point Clouds", CVPR 2015, M. Schoeler, J. Papon, F. Wörgötter. * \note It only uses points with a weight > 0 for the model calculation, but uses all points for the evaluation (scoring of the model) * Only use in conjunction with sac_model_plane * If you use this in a scientific work please cite the following paper: * M. Schoeler, J. Papon, F. Woergoetter * Constrained Planar Cuts - Object Partitioning for Point Clouds * In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (CVPR) 2015 * \author Markus Schoeler (mschoeler@web.de) * \ingroup segmentation */ class WeightedRandomSampleConsensus : public SampleConsensus { using SampleConsensusModelPtr = SampleConsensusModel::Ptr; public: using Ptr = shared_ptr; using ConstPtr = shared_ptr; /** \brief WeightedRandomSampleConsensus (Weighted RAndom SAmple Consensus) main constructor * \param[in] model a Sample Consensus model * \param[in] random if true set the random seed to the current time, else set to 12345 (default: false) */ WeightedRandomSampleConsensus (const SampleConsensusModelPtr &model, bool random = false) : SampleConsensus (model, random) { initialize (); } /** \brief WeightedRandomSampleConsensus (Weighted RAndom SAmple Consensus) main constructor * \param[in] model a Sample Consensus model * \param[in] threshold distance to model threshold * \param[in] random if true set the random seed to the current time, else set to 12345 (default: false) */ WeightedRandomSampleConsensus (const SampleConsensusModelPtr &model, double threshold, bool random = false) : SampleConsensus (model, threshold, random) { initialize (); } /** \brief Compute the actual model and find the inliers * \param[in] debug_verbosity_level enable/disable on-screen debug information and set the verbosity level */ bool computeModel (int debug_verbosity_level = 0) override; /** \brief Set the weights for the input points * \param[in] weights Weights for input samples. Negative weights are counted as penalty. */ void setWeights (const std::vector &weights, const bool directed_weights = false) { if (weights.size () != full_cloud_pt_indices_->size ()) { PCL_ERROR ("[pcl::WeightedRandomSampleConsensus::setWeights] Cannot assign weights. Weight vector needs to have the same length as the input pointcloud\n"); return; } weights_ = weights; model_pt_indices_->clear (); for (std::size_t i = 0; i < weights.size (); ++i) { if (weights[i] > std::numeric_limits::epsilon ()) model_pt_indices_->push_back (i); } use_directed_weights_ = directed_weights; } /** \brief Get the best score * \returns The best score found. */ double getBestScore () const { return (best_score_); } protected: /** \brief Initialize the model parameters. Called by the constructors. */ void initialize () { // Maximum number of trials before we give up. max_iterations_ = 10000; use_directed_weights_ = false; model_pt_indices_.reset (new Indices); full_cloud_pt_indices_.reset (new Indices (* (sac_model_->getIndices ()))); point_cloud_ptr_ = sac_model_->getInputCloud (); } /** \brief weight each positive weight point by the inner product between the normal and the plane normal */ bool use_directed_weights_; /** \brief vector of weights assigned to points. Set by the setWeights-method */ std::vector weights_; /** \brief The indices used for estimating the RANSAC model. Only those whose weight is > 0 */ pcl::IndicesPtr model_pt_indices_; /** \brief The complete list of indices used for the model evaluation */ pcl::IndicesPtr full_cloud_pt_indices_; /** \brief Pointer to the input PointCloud */ pcl::PointCloud::ConstPtr point_cloud_ptr_; /** \brief Highest score found so far */ double best_score_; }; }; } #ifdef PCL_NO_PRECOMPILE #include #elif defined(PCL_ONLY_CORE_POINT_TYPES) //pcl::PointXYZINormal is not a core point type (so we cannot use the precompiled classes here) #include #include #endif // PCL_NO_PRECOMPILE / PCL_ONLY_CORE_POINT_TYPES