提交 5d49eb10 编写于 作者: V Vincent Rabaud

- generate uniformly chosen samples in a common manner: much cleaner code and...

- generate uniformly chosen samples in a common manner: much cleaner code and linear time algorithm for sampling
- make the SAC tests more robust to slight changes in implementation

git-svn-id: svn+ssh://svn.pointclouds.org/pcl/trunk@681 a9d63959-f2ad-4865-b262-bf0e56cfafb6
上级 538c8c83
......@@ -42,79 +42,22 @@
#include "pcl/common/concatenate.h"
//////////////////////////////////////////////////////////////////////////
template <typename PointT> void
pcl::SampleConsensusModelCircle2D<PointT>::getSamples (int &iterations, std::vector<int> &samples)
template <typename PointT> bool
pcl::SampleConsensusModelCircle2D<PointT>::isSampleGood(const std::vector<int> &samples) const
{
// We're assuming that indices_ have already been set in the constructor
if (indices_->empty ())
{
PCL_ERROR ("[pcl::SampleConsensusModelCircle2D::getSamples] Empty set of indices given!");
return;
}
samples.resize (3);
double trand = indices_->size () / (RAND_MAX + 1.0);
// Check if we have enough points
if (samples.size () > indices_->size ())
{
PCL_ERROR ("[pcl::SampleConsensusModelCircle2D::getSamples] Can not select %zu unique points out of %zu!", samples.size (), indices_->size ());
// one of these will make it stop :) TODO static constant for each model that the method has to check
samples.clear ();
iterations = INT_MAX - 1;
return;
}
// Get a random number between 1 and max_indices
int idx = (int)(rand () * trand);
// Get the index
samples[0] = (*indices_)[idx];
// Get a second point which is different than the first
do
{
idx = (int)(rand () * trand);
samples[1] = (*indices_)[idx];
//iterations++;
} while (samples[1] == samples[0]);
//iterations--;
// Get the values at the two points
Eigen::Array2d p0 (input_->points[samples[0]].x, input_->points[samples[0]].y);
Eigen::Array2d p1 (input_->points[samples[1]].x, input_->points[samples[1]].y);
Eigen::Array2d p2 (input_->points[samples[2]].x, input_->points[samples[2]].y);
// Compute the segment values (in 2d) between p1 and p0
p1 -= p0;
// Compute the segment values (in 2d) between p2 and p0
p2 -= p0;
Eigen::Array2d dy1dy2;
int iter = 0;
do
{
// Get the third point, different from the first two
do
{
idx = (int)(rand () * trand);
samples[2] = (*indices_)[idx];
//iterations++;
} while ( (samples[2] == samples[1]) || (samples[2] == samples[0]) );
//iterations--;
Eigen::Array2d p2 (input_->points[samples[2]].x, input_->points[samples[2]].y);
// Compute the segment values (in 2d) between p2 and p0
p2 -= p0;
Eigen::Array2d dy1dy2 = p1 / p2;
dy1dy2 = p1 / p2;
++iter;
if (iter > MAX_ITERATIONS_COLLINEAR )
{
PCL_DEBUG ("[pcl::SampleConsensusModelCircle2D::getSamples] WARNING: Could not select 3 non collinear points in %d iterations!", MAX_ITERATIONS_COLLINEAR);
break;
}
//iterations++;
}
while ( (dy1dy2[0] == dy1dy2[1]) );
//iterations--;
return (dy1dy2[0] != dy1dy2[1]);
}
//////////////////////////////////////////////////////////////////////////
......
......@@ -44,46 +44,12 @@
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** \brief Get 2 random points with their normals as data samples and return them as point indices.
* \param iterations the internal number of iterations used by SAC methods
* \param samples the resultant model samples
* \note assumes unique points!
*/
template <typename PointT, typename PointNT> void
pcl::SampleConsensusModelCylinder<PointT, PointNT>::getSamples (int &iterations, std::vector<int> &samples)
template <typename PointT, typename PointNT> bool
pcl::SampleConsensusModelCylinder<PointT, PointNT>::isSampleGood(const std::vector<int> &samples) const
{
// We're assuming that indices_ have already been set in the constructor
if (indices_->empty ())
{
PCL_ERROR ("[pcl::SampleConsensusModelCylinder::getSamples] Empty set of indices given!");
return;
}
samples.resize (2);
double trand = indices_->size () / (RAND_MAX + 1.0);
// Check if we have enough points
if (samples.size () > indices_->size ())
{
PCL_ERROR ("[pcl::SampleConsensusModelCylinder::getSamples] Can not select %zu unique points out of %zu!", samples.size (), indices_->size ());
// one of these will make it stop :) TODO static constant for each model that the method has to check
samples.clear ();
iterations = INT_MAX - 1;
return;
}
// Get a random number between 1 and max_indices
int idx = (int)(rand () * trand);
// Get the index
samples[0] = (*indices_)[idx];
// Get a second point which is different than the first
do
{
idx = (int)(rand () * trand);
samples[1] = (*indices_)[idx];
//iterations++;
} while (samples[1] == samples[0]);
//iterations--;
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
......
......@@ -43,51 +43,10 @@
#include "pcl/common/concatenate.h"
//////////////////////////////////////////////////////////////////////////
template <typename PointT> void
pcl::SampleConsensusModelLine<PointT>::getSamples (int &iterations, std::vector<int> &samples)
template <typename PointT> bool
pcl::SampleConsensusModelLine<PointT>::isSampleGood(const std::vector<int> &samples) const
{
// We're assuming that indices_ have already been set in the constructor
if (indices_->empty ())
{
PCL_ERROR ("[pcl::SampleConsensusModelLine::getSamples] Empty set of indices given!");
return;
}
samples.resize (2);
double trand = indices_->size () / (RAND_MAX + 1.0);
// Check if we have enough points
if (samples.size () > indices_->size ())
{
PCL_ERROR ("[pcl::SampleConsensusModelLine::getSamples] Can not select %zu unique points out of %zu!", samples.size (), indices_->size ());
// one of these will make it stop :) TODO static constant for each model that the method has to check
samples.clear ();
iterations = INT_MAX - 1;
return;
}
// Get a random number between 1 and max_indices
int idx = (int)(rand () * trand);
// Get the index
samples[0] = (*indices_)[idx];
// Get a second point which is different than the first
int iter = 0;
do
{
idx = (int)(rand () * trand);
samples[1] = (*indices_)[idx];
++iter;
if (iter > MAX_ITERATIONS_UNIQUE )
{
PCL_DEBUG ("[pcl::SampleConsensusModelLine::getSamples] WARNING: Could not select 2 unique points in %d iterations (%zu indices)!", MAX_ITERATIONS_UNIQUE, indices_->size ());
break;
}
//iterations++;
}
while (samples[1] == samples[0]);
//iterations--;
return true;
}
//////////////////////////////////////////////////////////////////////////
......
......@@ -44,79 +44,23 @@
#include "pcl/common/concatenate.h"
//////////////////////////////////////////////////////////////////////////
template <typename PointT> void
pcl::SampleConsensusModelPlane<PointT>::getSamples (int &iterations, std::vector<int> &samples)
template <typename PointT> bool
pcl::SampleConsensusModelPlane<PointT>::isSampleGood(const std::vector<int> &samples) const
{
// We're assuming that indices_ have already been set in the constructor
if (indices_->empty ())
{
PCL_ERROR ("[pcl::SampleConsensusModelPlane::getSamples] Empty set of indices given!");
return;
}
samples.resize (3);
double trand = indices_->size () / (RAND_MAX + 1.0);
// Check if we have enough points
if (samples.size () > indices_->size ())
{
PCL_ERROR ("[pcl::SampleConsensusModelPlane::getSamples] Can not select %zu unique points out of %zu!", samples.size (), indices_->size ());
// one of these will make it stop :) TODO static constant for each model that the method has to check
samples.clear ();
iterations = INT_MAX - 1;
return;
}
// Get a random number between 1 and max_indices
int idx = (int)(rand () * trand);
// Get the index
samples[0] = (*indices_)[idx];
// Get a second point which is different than the first
do
{
idx = (int)(rand () * trand);
samples[1] = (*indices_)[idx];
//iterations++;
} while (samples[1] == samples[0]);
//iterations--;
// Get the values at the two points
pcl::Array4fMapConst p0 = input_->points[samples[0]].getArray4fMap ();
pcl::Array4fMapConst p1 = input_->points[samples[1]].getArray4fMap ();
pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap ();
// Compute the segment values (in 3d) between p1 and p0
Eigen::Array4f p1p0 = p1 - p0;
Eigen::Array4f dy1dy2;
int iter = 0;
do
{
// Get the third point, different from the first two
do
{
idx = (int)(rand () * trand);
samples[2] = (*indices_)[idx];
//iterations++;
} while ( (samples[2] == samples[1]) || (samples[2] == samples[0]) );
//iterations--;
pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap ();
// Compute the segment values (in 3d) between p2 and p0
Eigen::Array4f p2p0 = p2 - p0;
// Compute the segment values (in 3d) between p2 and p0
Eigen::Array4f p2p0 = p2 - p0;
Eigen::Array4f dy1dy2 = p1p0 / p2p0;
dy1dy2 = p1p0 / p2p0;
++iter;
if (iter > MAX_ITERATIONS_COLLINEAR )
{
PCL_DEBUG ("[pcl::SampleConsensusModelPlane::getSamples] WARNING: Could not select 3 non collinear points in %d iterations!", MAX_ITERATIONS_COLLINEAR);
break;
}
//iterations++;
}
while ( (dy1dy2[0] == dy1dy2[1]) && (dy1dy2[2] == dy1dy2[1]) );
//iterations--;
return ( (dy1dy2[0] != dy1dy2[1]) || (dy1dy2[2] != dy1dy2[1]) );
}
//////////////////////////////////////////////////////////////////////////
......
......@@ -42,43 +42,22 @@
#include "pcl/common/rigid_transforms.h"
//////////////////////////////////////////////////////////////////////////
template <typename PointT> void
pcl::SampleConsensusModelRegistration<PointT>::getSamples (int &iterations, std::vector<int> &samples)
template <typename PointT> bool
pcl::SampleConsensusModelRegistration<PointT>::isSampleGood(const std::vector<int> &samples) const
{
// We're assuming that indices_ have already been set in the constructor
if (indices_->size () < 3)
{
PCL_ERROR ("[pcl::SampleConsensusModelRegistration::getSamples] Can not select %zu unique points out of %zu!", samples.size (), indices_->size ());
// one of these will make it stop :) TODO static constant for each model that the method has to check
samples.clear ();
iterations = INT_MAX - 1;
return;
}
samples.resize (3);
// Get a second point which is different than the first
Eigen::Array4f p1p0, p2p0, p2p1;
for(unsigned int iter = 0; iter <= MAX_ITERATIONS_COLLINEAR; ++iter)
{
// Choose thre random indices
SampleConsensusModel<PointT>::drawIndexSample (samples);
// Get the values at the points
pcl::Array4fMapConst p0 = input_->points[samples[0]].getArray4fMap ();
pcl::Array4fMapConst p1 = input_->points[samples[1]].getArray4fMap ();
pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap ();
// Compute the segment values (in 3d) between p1 and p0
p1p0 = p1 - p0;
p2p0 = p2 - p0;
p2p1 = p2 - p1;
if ((p1p0.matrix ().squaredNorm () > sample_dist_thresh_) && (p2p0.matrix ().squaredNorm ()
> sample_dist_thresh_) && (p2p1.matrix ().squaredNorm () > sample_dist_thresh_))
return;
}
PCL_DEBUG ("[pcl::SampleConsensusModelRegistration::getSamples] WARNING: Could not select 3 non collinear points in %d iterations!", MAX_ITERATIONS_COLLINEAR);
samples.clear ();
// Get the values at the points
pcl::Array4fMapConst p0 = input_->points[samples[0]].getArray4fMap();
pcl::Array4fMapConst p1 = input_->points[samples[1]].getArray4fMap();
pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap();
// Compute the segment values (in 3d) between p1 and p0
p1p0 = p1 - p0;
p2p0 = p2 - p0;
p2p1 = p2 - p1;
return ((p1p0.matrix().squaredNorm() > sample_dist_thresh_) && (p2p0.matrix().squaredNorm() > sample_dist_thresh_)
&& (p2p1.matrix().squaredNorm() > sample_dist_thresh_));
}
//////////////////////////////////////////////////////////////////////////
......
......@@ -41,89 +41,22 @@
#include "pcl/sample_consensus/sac_model_sphere.h"
//////////////////////////////////////////////////////////////////////////
template <typename PointT> void
pcl::SampleConsensusModelSphere<PointT>::getSamples (int &iterations, std::vector<int> &samples)
template <typename PointT> bool
pcl::SampleConsensusModelSphere<PointT>::isSampleGood(const std::vector<int> &samples) const
{
// We're assuming that indices_ have already been set in the constructor
if (indices_->empty ())
{
PCL_ERROR ("[pcl::SampleConsensusModelSphere::getSamples] Empty set of indices given!");
return;
}
samples.resize (4);
double trand = indices_->size () / (RAND_MAX + 1.0);
// Check if we have enough points
if (samples.size () > indices_->size ())
{
PCL_ERROR ("[pcl::SampleConsensusModelSphere::getSamples] Can not select %zu unique points out of %zu!", samples.size (), indices_->size ());
// one of these will make it stop :) TODO static constant for each model that the method has to check
samples.clear ();
iterations = INT_MAX - 1;
return;
}
// Get a random number between 1 and max_indices
int idx = (int)(rand () * trand);
// Get the index
samples[0] = (*indices_)[idx];
// Get a second point which is different than the first
do
{
idx = (int)(rand () * trand);
samples[1] = (*indices_)[idx];
//iterations++;
} while (samples[1] == samples[0]);
//iterations--;
// Get the values at the two points
pcl::Array4fMapConst p0 = input_->points[samples[0]].getArray4fMap ();
pcl::Array4fMapConst p1 = input_->points[samples[1]].getArray4fMap ();
pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap ();
// Compute the segment values (in 3d) between p1 and p0
Eigen::Array4f p1p0 = p1 - p0;
// Compute the segment values (in 3d) between p2 and p0
Eigen::Array4f p2p0 = p2 - p0;
Eigen::Array4f dy1dy2;
int iter = 0;
do
{
// Get the third point, different from the first two
do
{
idx = (int)(rand () * trand);
samples[2] = (*indices_)[idx];
//iterations++;
} while ( (samples[2] == samples[1]) || (samples[2] == samples[0]) );
//iterations--;
pcl::Array4fMapConst p2 = input_->points[samples[2]].getArray4fMap ();
// Compute the segment values (in 3d) between p2 and p0
Eigen::Array4f p2p0 = p2 - p0;
dy1dy2 = p1p0 / p2p0;
++iter;
if (iter > MAX_ITERATIONS_COLLINEAR )
{
PCL_DEBUG ("[pcl::SampleConsensusModelSphere::getSamples] WARNING: Could not select 3 non collinear points in %d iterations!", MAX_ITERATIONS_COLLINEAR);
break;
}
//iterations++;
}
while ( (dy1dy2[0] == dy1dy2[1]) && (dy1dy2[2] == dy1dy2[1]) );
//iterations--;
// Need to improve this: we need 4 points, 3 non-collinear always, and the 4th should not be in the same plane as the other 3
// otherwise we can encounter degenerate cases
do
{
samples[3] = (int)(rand () * trand);
//iterations++;
} while ( (samples[3] == samples[2]) || (samples[3] == samples[1]) || (samples[3] == samples[0]) );
//iterations--;
Eigen::Array4f dy1dy2 = p1p0 / p2p0;
return true;
}
//////////////////////////////////////////////////////////////////////////
......
......@@ -67,9 +67,18 @@ typedef std::map<pcl::SacModel, unsigned int>::value_type SampleSizeModel;
const static SampleSizeModel sample_size_pairs[] = {SampleSizeModel (pcl::SACMODEL_PLANE, 3),
SampleSizeModel (pcl::SACMODEL_LINE,2),
SampleSizeModel (pcl::SACMODEL_CIRCLE2D, 3),
//SampleSizeModel (pcl::SACMODEL_CIRCLE3D, 3),
SampleSizeModel (pcl::SACMODEL_SPHERE, 4),
SampleSizeModel (pcl::SACMODEL_CYLINDER, 2),
SampleSizeModel (pcl::SACMODEL_REGISTRATION, 3)};
//SampleSizeModel (pcl::SACMODEL_CONE, 2),
//SampleSizeModel (pcl::SACMODEL_TORUS, 2),
//SampleSizeModel (pcl::PARALLEL_LINE, 2),
//SampleSizeModel (pcl::PERPENDICULAR_LINE, 2),
//SampleSizeModel (pcl::PARALLEL_LINES, 2),
SampleSizeModel (pcl::SACMODEL_NORMAL_PLANE, 3),
SampleSizeModel (pcl::SACMODEL_REGISTRATION, 3),
SampleSizeModel (pcl::SACMODEL_PARALLEL_PLANE, 3),
SampleSizeModel (pcl::SACMODEL_NORMAL_PARALLEL_PLANE, 3)};
namespace pcl
{
......
......@@ -109,8 +109,33 @@ namespace pcl
* \param iterations the internal number of iterations used by SAC methods
* \param samples the resultant model samples
*/
virtual void
getSamples (int &iterations, std::vector<int> &samples) = 0;
void getSamples(int &iterations, std::vector<int> &samples)
{
// We're assuming that indices_ have already been set in the constructor
if (indices_->size () < getSampleSize())
{
PCL_ERROR ("[pcl::SampleConsensusModel::getSamples] Can not select %zu unique points out of %zu!",
samples.size (), indices_->size ());
// one of these will make it stop :)
samples.clear ();
iterations = INT_MAX - 1;
return;
}
// Get a second point which is different than the first
samples.resize(getSampleSize());
for(unsigned int iter = 0; iter < max_sample_checks_; ++iter)
{
// Choose the random indices
SampleConsensusModel<PointT>::drawIndexSample (samples);
// If it's a good sample, stop here
if (isSampleGood(samples))
return;
}
PCL_DEBUG ("[pcl::SampleConsensusModel::getSamples] WARNING: Could not select 3 non collinear points in %d iterations!", max_sample_checks_);
samples.clear();
}
/** \brief Check whether the given index samples can form a valid model,
* compute the model coefficients from these samples and store them
......@@ -206,6 +231,7 @@ namespace pcl
for (size_t i = 0; i < cloud->points.size (); ++i)
(*indices_)[i] = i;
}
shuffled_indices_ = *indices_;
}
/** \brief Get a pointer to the input point cloud dataset. */
......@@ -272,7 +298,7 @@ namespace pcl
/** \brief Fills a sample array with random samples from the indices_ vector
* Sure, there are some swaps in there but it is linear in the size of the sample, no stupid while loop to
* compare the elements between them
* \param model_coefficients the set of model coefficients
* \param sample the set of indices of target_ to analyze
*/
inline void
drawIndexSample (std::vector<int> & sample)
......@@ -292,12 +318,22 @@ namespace pcl
virtual inline bool
isModelValid (const Eigen::VectorXf &model_coefficients) = 0;
/** \brief Check if a sample of indices results in a good sample of points
* indices. Pure virtual.
* \param samples the resultant index samples
*/
virtual bool
isSampleGood(const std::vector<int> &samples) const = 0;
/** \brief A boost shared pointer to the point cloud data array. */
PointCloudConstPtr input_;
/** \brief A pointer to the vector of point indices to use. */
IndicesPtr indices_;
/** The maximum number of samples to try until we get a good one */
static const unsigned int max_sample_checks_ = 1000;
/** \brief The minimum and maximum radius limits for the model.
* Applicable to all models that estimate a radius.
*/
......
......@@ -137,6 +137,13 @@ namespace pcl
bool
isModelValid (const Eigen::VectorXf &model_coefficients);
/** \brief Check if a sample of indices results in a good sample of points
* indices. Pure virtual.
* \param samples the resultant index samples
*/
bool
isSampleGood(const std::vector<int> &samples) const;
private:
/** \brief Temporary boost mutex for \a tmp_inliers_ */
boost::mutex tmp_mutex_;
......@@ -144,9 +151,6 @@ namespace pcl
/** \brief Temporary pointer to a list of given indices for optimizeModelCoefficients () */
const std::vector<int> *tmp_inliers_;
/** \brief Define the maximum number of iterations for collinearity checks */
const static int MAX_ITERATIONS_COLLINEAR = 1000;
/** \brief Cost function to be minimized
* \param p a pointer to our data structure array
* \param m the number of functions
......
......@@ -196,6 +196,13 @@ namespace pcl
*/
bool isModelValid (const Eigen::VectorXf &model_coefficients);
/** \brief Check if a sample of indices results in a good sample of points
* indices. Pure virtual.
* \param samples the resultant index samples
*/
bool
isSampleGood(const std::vector<int> &samples) const;
private:
/** \brief The axis along which we need to search for a plane perpendicular to. */
Eigen::Vector3f axis_;
......@@ -209,9 +216,6 @@ namespace pcl
/** \brief temporary pointer to a list of given indices for optimizeModelCoefficients () */
const std::vector<int> *tmp_inliers_;
/** \brief Define the maximum number of iterations for collinearity checks */
const static int MAX_ITERATIONS_COLLINEAR = 1000;
/** \brief Cost function to be minimized
* \param p a pointer to our data structure array
* \param m the number of functions
......
......@@ -137,9 +137,12 @@ namespace pcl
return (true);
}
private:
/** \brief Define the maximum number of iterations for unique points search. */
const static int MAX_ITERATIONS_UNIQUE = 1000;
/** \brief Check if a sample of indices results in a good sample of points
* indices. Pure virtual.
* \param samples the resultant index samples
*/
bool
isSampleGood(const std::vector<int> &samples) const;
};
}
......
......@@ -193,8 +193,12 @@ namespace pcl
}
private:
/** \brief Define the maximum number of iterations for collinearity checks */
const static int MAX_ITERATIONS_COLLINEAR = 1000;
/** \brief Check if a sample of indices results in a good sample of points
* indices. Pure virtual.
* \param samples the resultant index samples
*/
bool
isSampleGood(const std::vector<int> &samples) const;
};
}
......
......@@ -139,15 +139,6 @@ namespace pcl
indices_tgt_.reset (new std::vector<int> (indices_tgt));
}
/** \brief Get 3 random indices from a subset of given indices.
* \param iterations the internal number of iterations used by SAC methods
* \param samples the resultant model samples
* \note assumes unique points!
*/
void
getSamples (int &iterations,
std::vector<int> &samples);
/** \brief Compute a 4x4 rigid transformation matrix from the samples given
* \param samples the indices found as good candidates for creating a valid model
* \param model_coefficients the resultant model coefficients
......@@ -213,6 +204,13 @@ namespace pcl
return (true);
}
/** \brief Check if a sample of indices results in a good sample of points
* indices. Pure virtual.
* \param samples the resultant index samples
*/
bool
isSampleGood(const std::vector<int> &samples) const;
private:
/** \brief A boost shared pointer to the target point cloud data array. */
PointCloudConstPtr target_;
......@@ -222,9 +220,6 @@ namespace pcl
/** \brief Internal distance threshold used for the sample selection step. */
double sample_dist_thresh_;
/** \brief Define the maximum number of iterations for collinearity checks */
const static unsigned int MAX_ITERATIONS_COLLINEAR = 1000;
};
}
......
......@@ -163,6 +163,13 @@ namespace pcl
return (true);
}
/** \brief Check if a sample of indices results in a good sample of points
* indices. Pure virtual.
* \param samples the resultant index samples
*/
bool
isSampleGood(const std::vector<int> &samples) const;
private:
/** \brief Temporary boost mutex for \a tmp_inliers_ */
boost::mutex tmp_mutex_;
......@@ -170,9 +177,6 @@ namespace pcl
/** \brief Temporary pointer to a list of given indices for optimizeModelCoefficients () */
const std::vector<int> *tmp_inliers_;
/** \brief Define the maximum number of iterations for collinearity checks */
const static int MAX_ITERATIONS_COLLINEAR = 1000;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////(
/** \brief Cost function to be minimized
* \param p a pointer to our data structure array
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册