442 lines
17 KiB
C++

/*
* Software License Agreement (BSD License)
*
* Point Cloud Library (PCL) - www.pointclouds.org
* Copyright (c) 2010-2012, Willow Garage, 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.
*
* $Id$
*
*/
#pragma once
#include <pcl/pcl_base.h>
#include <pcl/PointIndices.h>
#include <pcl/ModelCoefficients.h>
// Sample Consensus methods
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/sac.h>
// Sample Consensus models
#include <pcl/sample_consensus/model_types.h>
#include <pcl/sample_consensus/sac_model.h>
#include <pcl/search/search.h>
namespace pcl
{
/** \brief @b SACSegmentation represents the Nodelet segmentation class for
* Sample Consensus methods and models, in the sense that it just creates a
* Nodelet wrapper for generic-purpose SAC-based segmentation.
* \author Radu Bogdan Rusu
* \ingroup segmentation
*/
template <typename PointT>
class SACSegmentation : public PCLBase<PointT>
{
using PCLBase<PointT>::initCompute;
using PCLBase<PointT>::deinitCompute;
public:
using PCLBase<PointT>::input_;
using PCLBase<PointT>::indices_;
using PointCloud = pcl::PointCloud<PointT>;
using PointCloudPtr = typename PointCloud::Ptr;
using PointCloudConstPtr = typename PointCloud::ConstPtr;
using SearchPtr = typename pcl::search::Search<PointT>::Ptr;
using SampleConsensusPtr = typename SampleConsensus<PointT>::Ptr;
using SampleConsensusModelPtr = typename SampleConsensusModel<PointT>::Ptr;
/** \brief Empty constructor.
* \param[in] random if true set the random seed to the current time, else set to 12345 (default: false)
*/
SACSegmentation (bool random = false)
: model_ ()
, sac_ ()
, model_type_ (-1)
, method_type_ (0)
, threshold_ (0)
, optimize_coefficients_ (true)
, radius_min_ (-std::numeric_limits<double>::max ())
, radius_max_ (std::numeric_limits<double>::max ())
, samples_radius_ (0.0)
, samples_radius_search_ ()
, eps_angle_ (0.0)
, axis_ (Eigen::Vector3f::Zero ())
, max_iterations_ (50)
, threads_ (-1)
, probability_ (0.99)
, random_ (random)
{
}
/** \brief Empty destructor. */
~SACSegmentation () { /*srv_.reset ();*/ };
/** \brief The type of model to use (user given parameter).
* \param[in] model the model type (check \a model_types.h)
*/
inline void
setModelType (int model) { model_type_ = model; }
/** \brief Get the type of SAC model used. */
inline int
getModelType () const { return (model_type_); }
/** \brief Get a pointer to the SAC method used. */
inline SampleConsensusPtr
getMethod () const { return (sac_); }
/** \brief Get a pointer to the SAC model used. */
inline SampleConsensusModelPtr
getModel () const { return (model_); }
/** \brief The type of sample consensus method to use (user given parameter).
* \param[in] method the method type (check \a method_types.h)
*/
inline void
setMethodType (int method) { method_type_ = method; }
/** \brief Get the type of sample consensus method used. */
inline int
getMethodType () const { return (method_type_); }
/** \brief Distance to the model threshold (user given parameter).
* \param[in] threshold the distance threshold to use
*/
inline void
setDistanceThreshold (double threshold) { threshold_ = threshold; }
/** \brief Get the distance to the model threshold. */
inline double
getDistanceThreshold () const { return (threshold_); }
/** \brief Set the maximum number of iterations before giving up.
* \param[in] max_iterations the maximum number of iterations the sample consensus method will run
*/
inline void
setMaxIterations (int max_iterations) { max_iterations_ = max_iterations; }
/** \brief Get maximum number of iterations before giving up. */
inline int
getMaxIterations () const { return (max_iterations_); }
/** \brief Set the probability of choosing at least one sample free from outliers.
* \param[in] probability the model fitting probability
*/
inline void
setProbability (double probability) { probability_ = probability; }
/** \brief Get the probability of choosing at least one sample free from outliers. */
inline double
getProbability () const { return (probability_); }
/** \brief Set the number of threads to use or turn off parallelization.
* \param[in] nr_threads the number of hardware threads to use (0 sets the value automatically, a negative number turns parallelization off)
* \note Not all SAC methods have a parallel implementation. Some will ignore this setting.
*/
inline void
setNumberOfThreads (const int nr_threads = -1) { threads_ = nr_threads; }
/** \brief Set to true if a coefficient refinement is required.
* \param[in] optimize true for enabling model coefficient refinement, false otherwise
*/
inline void
setOptimizeCoefficients (bool optimize) { optimize_coefficients_ = optimize; }
/** \brief Get the coefficient refinement internal flag. */
inline bool
getOptimizeCoefficients () const { return (optimize_coefficients_); }
/** \brief Set the minimum and maximum allowable radius limits for the model (applicable to models that estimate
* a radius)
* \param[in] min_radius the minimum radius model
* \param[in] max_radius the maximum radius model
*/
inline void
setRadiusLimits (const double &min_radius, const double &max_radius)
{
radius_min_ = min_radius;
radius_max_ = max_radius;
}
/** \brief Get the minimum and maximum allowable radius limits for the model as set by the user.
* \param[out] min_radius the resultant minimum radius model
* \param[out] max_radius the resultant maximum radius model
*/
inline void
getRadiusLimits (double &min_radius, double &max_radius)
{
min_radius = radius_min_;
max_radius = radius_max_;
}
/** \brief Set the maximum distance allowed when drawing random samples
* \param[in] radius the maximum distance (L2 norm)
* \param search
*/
inline void
setSamplesMaxDist (const double &radius, SearchPtr search)
{
samples_radius_ = radius;
samples_radius_search_ = search;
}
/** \brief Get maximum distance allowed when drawing random samples
*
* \param[out] radius the maximum distance (L2 norm)
*/
inline void
getSamplesMaxDist (double &radius)
{
radius = samples_radius_;
}
/** \brief Set the axis along which we need to search for a model perpendicular to.
* \param[in] ax the axis along which we need to search for a model perpendicular to
*/
inline void
setAxis (const Eigen::Vector3f &ax) { axis_ = ax; }
/** \brief Get the axis along which we need to search for a model perpendicular to. */
inline Eigen::Vector3f
getAxis () const { return (axis_); }
/** \brief Set the angle epsilon (delta) threshold.
* \param[in] ea the maximum allowed difference between the model normal and the given axis in radians.
*/
inline void
setEpsAngle (double ea) { eps_angle_ = ea; }
/** \brief Get the epsilon (delta) model angle threshold in radians. */
inline double
getEpsAngle () const { return (eps_angle_); }
/** \brief Base method for segmentation of a model in a PointCloud given by <setInputCloud (), setIndices ()>
* \param[out] inliers the resultant point indices that support the model found (inliers)
* \param[out] model_coefficients the resultant model coefficients
*/
virtual void
segment (PointIndices &inliers, ModelCoefficients &model_coefficients);
protected:
/** \brief Initialize the Sample Consensus model and set its parameters.
* \param[in] model_type the type of SAC model that is to be used
*/
virtual bool
initSACModel (const int model_type);
/** \brief Initialize the Sample Consensus method and set its parameters.
* \param[in] method_type the type of SAC method to be used
*/
virtual void
initSAC (const int method_type);
/** \brief The model that needs to be segmented. */
SampleConsensusModelPtr model_;
/** \brief The sample consensus segmentation method. */
SampleConsensusPtr sac_;
/** \brief The type of model to use (user given parameter). */
int model_type_;
/** \brief The type of sample consensus method to use (user given parameter). */
int method_type_;
/** \brief Distance to the model threshold (user given parameter). */
double threshold_;
/** \brief Set to true if a coefficient refinement is required. */
bool optimize_coefficients_;
/** \brief The minimum and maximum radius limits for the model. Applicable to all models that estimate a radius. */
double radius_min_, radius_max_;
/** \brief The maximum distance of subsequent samples from the first (radius search) */
double samples_radius_;
/** \brief The search object for picking subsequent samples using radius search */
SearchPtr samples_radius_search_;
/** \brief The maximum allowed difference between the model normal and the given axis. */
double eps_angle_;
/** \brief The axis along which we need to search for a model perpendicular to. */
Eigen::Vector3f axis_;
/** \brief Maximum number of iterations before giving up (user given parameter). */
int max_iterations_;
/** \brief The number of threads the scheduler should use, or a negative number if no parallelization is wanted. */
int threads_;
/** \brief Desired probability of choosing at least one sample free from outliers (user given parameter). */
double probability_;
/** \brief Set to true if we need a random seed. */
bool random_;
/** \brief Class get name method. */
virtual std::string
getClassName () const { return ("SACSegmentation"); }
};
/** \brief @b SACSegmentationFromNormals represents the PCL nodelet segmentation class for Sample Consensus methods and
* models that require the use of surface normals for estimation.
* \ingroup segmentation
*/
template <typename PointT, typename PointNT>
class SACSegmentationFromNormals: public SACSegmentation<PointT>
{
using SACSegmentation<PointT>::model_;
using SACSegmentation<PointT>::model_type_;
using SACSegmentation<PointT>::radius_min_;
using SACSegmentation<PointT>::radius_max_;
using SACSegmentation<PointT>::eps_angle_;
using SACSegmentation<PointT>::axis_;
using SACSegmentation<PointT>::random_;
public:
using PCLBase<PointT>::input_;
using PCLBase<PointT>::indices_;
using PointCloud = typename SACSegmentation<PointT>::PointCloud;
using PointCloudPtr = typename PointCloud::Ptr;
using PointCloudConstPtr = typename PointCloud::ConstPtr;
using PointCloudN = pcl::PointCloud<PointNT>;
using PointCloudNPtr = typename PointCloudN::Ptr;
using PointCloudNConstPtr = typename PointCloudN::ConstPtr;
using SampleConsensusPtr = typename SampleConsensus<PointT>::Ptr;
using SampleConsensusModelPtr = typename SampleConsensusModel<PointT>::Ptr;
using SampleConsensusModelFromNormalsPtr = typename SampleConsensusModelFromNormals<PointT, PointNT>::Ptr;
/** \brief Empty constructor.
* \param[in] random if true set the random seed to the current time, else set to 12345 (default: false)
*/
SACSegmentationFromNormals (bool random = false)
: SACSegmentation<PointT> (random)
, normals_ ()
, distance_weight_ (0.1)
, distance_from_origin_ (0)
, min_angle_ (0.0)
, max_angle_ (M_PI_2)
{};
/** \brief Provide a pointer to the input dataset that contains the point normals of
* the XYZ dataset.
* \param[in] normals the const shared pointer to a PointCloud message
*/
inline void
setInputNormals (const PointCloudNConstPtr &normals) { normals_ = normals; }
/** \brief Get a pointer to the normals of the input XYZ point cloud dataset. */
inline PointCloudNConstPtr
getInputNormals () const { return (normals_); }
/** \brief Set the relative weight (between 0 and 1) to give to the angular
* distance (0 to pi/2) between point normals and the plane normal.
* \param[in] distance_weight the distance/angular weight
*/
inline void
setNormalDistanceWeight (double distance_weight) { distance_weight_ = distance_weight; }
/** \brief Get the relative weight (between 0 and 1) to give to the angular distance (0 to pi/2) between point
* normals and the plane normal. */
inline double
getNormalDistanceWeight () const { return (distance_weight_); }
/** \brief Set the minimum opning angle for a cone model.
* \param min_angle the opening angle which we need minimum to validate a cone model.
* \param max_angle the opening angle which we need maximum to validate a cone model.
*/
inline void
setMinMaxOpeningAngle (const double &min_angle, const double &max_angle)
{
min_angle_ = min_angle;
max_angle_ = max_angle;
}
/** \brief Get the opening angle which we need minimum to validate a cone model. */
inline void
getMinMaxOpeningAngle (double &min_angle, double &max_angle)
{
min_angle = min_angle_;
max_angle = max_angle_;
}
/** \brief Set the distance we expect a plane model to be from the origin
* \param[in] d distance from the template plane model to the origin
*/
inline void
setDistanceFromOrigin (const double d) { distance_from_origin_ = d; }
/** \brief Get the distance of a plane model from the origin. */
inline double
getDistanceFromOrigin () const { return (distance_from_origin_); }
protected:
/** \brief A pointer to the input dataset that contains the point normals of the XYZ dataset. */
PointCloudNConstPtr normals_;
/** \brief The relative weight (between 0 and 1) to give to the angular
* distance (0 to pi/2) between point normals and the plane normal.
*/
double distance_weight_;
/** \brief The distance from the template plane to the origin. */
double distance_from_origin_;
/** \brief The minimum and maximum allowed opening angle of valid cone model. */
double min_angle_;
double max_angle_;
/** \brief Initialize the Sample Consensus model and set its parameters.
* \param[in] model_type the type of SAC model that is to be used
*/
bool
initSACModel (const int model_type) override;
/** \brief Class get name method. */
std::string
getClassName () const override { return ("SACSegmentationFromNormals"); }
};
}
#ifdef PCL_NO_PRECOMPILE
#include <pcl/segmentation/impl/sac_segmentation.hpp>
#endif