38 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_CYLINDER_H_
39 #define PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_CYLINDER_H_
43 #include <unsupported/Eigen/NonLinearOptimization>
46 template <
typename Po
intT,
typename Po
intNT>
bool
53 template <
typename Po
intT,
typename Po
intNT>
bool
55 const std::vector<int> &samples, Eigen::VectorXf &model_coefficients)
58 if (samples.size () != 2)
60 PCL_ERROR (
"[pcl::SampleConsensusModelCylinder::computeModelCoefficients] Invalid set of samples given (%zu)!\n", samples.size ());
66 PCL_ERROR (
"[pcl::SampleConsensusModelCylinder::computeModelCoefficients] No input dataset containing normals was given!\n");
70 Eigen::Vector4f p1 (input_->points[samples[0]].x, input_->points[samples[0]].y, input_->points[samples[0]].z, 0);
71 Eigen::Vector4f p2 (input_->points[samples[1]].x, input_->points[samples[1]].y, input_->points[samples[1]].z, 0);
73 Eigen::Vector4f n1 (normals_->points[samples[0]].normal[0], normals_->points[samples[0]].normal[1], normals_->points[samples[0]].normal[2], 0);
74 Eigen::Vector4f n2 (normals_->points[samples[1]].normal[0], normals_->points[samples[1]].normal[1], normals_->points[samples[1]].normal[2], 0);
75 Eigen::Vector4f w = n1 + p1 - p2;
77 float a = n1.dot (n1);
78 float b = n1.dot (n2);
79 float c = n2.dot (n2);
82 float denominator = a*c - b*b;
85 if (denominator < 1e-8)
88 tc = (b > c ? d / b : e / c);
92 sc = (b*e - c*d) / denominator;
93 tc = (a*e - b*d) / denominator;
97 Eigen::Vector4f line_pt = p1 + n1 + sc * n1;
98 Eigen::Vector4f line_dir = p2 + tc * n2 - line_pt;
99 line_dir.normalize ();
101 model_coefficients.resize (7);
103 model_coefficients[0] = line_pt[0];
104 model_coefficients[1] = line_pt[1];
105 model_coefficients[2] = line_pt[2];
107 model_coefficients[3] = line_dir[0];
108 model_coefficients[4] = line_dir[1];
109 model_coefficients[5] = line_dir[2];
113 if (model_coefficients[6] > radius_max_ || model_coefficients[6] < radius_min_)
120 template <
typename Po
intT,
typename Po
intNT>
void
122 const Eigen::VectorXf &model_coefficients, std::vector<double> &distances)
125 if (!isModelValid (model_coefficients))
131 distances.resize (indices_->size ());
133 Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
134 Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
135 float ptdotdir = line_pt.dot (line_dir);
136 float dirdotdir = 1.0f / line_dir.dot (line_dir);
138 for (
size_t i = 0; i < indices_->size (); ++i)
143 Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, input_->points[(*indices_)[i]].y, input_->points[(*indices_)[i]].z, 0);
144 Eigen::Vector4f n (normals_->points[(*indices_)[i]].normal[0], normals_->points[(*indices_)[i]].normal[1], normals_->points[(*indices_)[i]].normal[2], 0);
146 double d_euclid = fabs (pointToLineDistance (pt, model_coefficients) - model_coefficients[6]);
149 float k = (pt.dot (line_dir) - ptdotdir) * dirdotdir;
150 Eigen::Vector4f pt_proj = line_pt + k * line_dir;
151 Eigen::Vector4f dir = pt - pt_proj;
156 d_normal = (std::min) (d_normal, M_PI - d_normal);
158 distances[i] = fabs (normal_distance_weight_ * d_normal + (1 - normal_distance_weight_) * d_euclid);
163 template <
typename Po
intT,
typename Po
intNT>
void
165 const Eigen::VectorXf &model_coefficients,
const double threshold, std::vector<int> &inliers)
168 if (!isModelValid (model_coefficients))
175 inliers.resize (indices_->size ());
177 Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
178 Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
179 float ptdotdir = line_pt.dot (line_dir);
180 float dirdotdir = 1.0f / line_dir.dot (line_dir);
182 for (
size_t i = 0; i < indices_->size (); ++i)
186 Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, input_->points[(*indices_)[i]].y, input_->points[(*indices_)[i]].z, 0);
187 Eigen::Vector4f n (normals_->points[(*indices_)[i]].normal[0], normals_->points[(*indices_)[i]].normal[1], normals_->points[(*indices_)[i]].normal[2], 0);
188 double d_euclid = fabs (pointToLineDistance (pt, model_coefficients) - model_coefficients[6]);
191 float k = (pt.dot (line_dir) - ptdotdir) * dirdotdir;
192 Eigen::Vector4f pt_proj = line_pt + k * line_dir;
193 Eigen::Vector4f dir = pt - pt_proj;
198 d_normal = (std::min) (d_normal, M_PI - d_normal);
200 if (fabs (normal_distance_weight_ * d_normal + (1 - normal_distance_weight_) * d_euclid) < threshold)
203 inliers[nr_p] = (*indices_)[i];
207 inliers.resize (nr_p);
211 template <
typename Po
intT,
typename Po
intNT>
int
213 const Eigen::VectorXf &model_coefficients,
const double threshold)
216 if (!isModelValid (model_coefficients))
221 Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
222 Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
223 float ptdotdir = line_pt.dot (line_dir);
224 float dirdotdir = 1.0f / line_dir.dot (line_dir);
226 for (
size_t i = 0; i < indices_->size (); ++i)
230 Eigen::Vector4f pt (input_->points[(*indices_)[i]].x, input_->points[(*indices_)[i]].y, input_->points[(*indices_)[i]].z, 0);
231 Eigen::Vector4f n (normals_->points[(*indices_)[i]].normal[0], normals_->points[(*indices_)[i]].normal[1], normals_->points[(*indices_)[i]].normal[2], 0);
232 double d_euclid = fabs (pointToLineDistance (pt, model_coefficients) - model_coefficients[6]);
235 float k = (pt.dot (line_dir) - ptdotdir) * dirdotdir;
236 Eigen::Vector4f pt_proj = line_pt + k * line_dir;
237 Eigen::Vector4f dir = pt - pt_proj;
242 d_normal = (std::min) (d_normal, M_PI - d_normal);
244 if (fabs (normal_distance_weight_ * d_normal + (1 - normal_distance_weight_) * d_euclid) < threshold)
251 template <
typename Po
intT,
typename Po
intNT>
void
253 const std::vector<int> &inliers,
const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients)
255 optimized_coefficients = model_coefficients;
258 if (model_coefficients.size () != 7)
260 PCL_ERROR (
"[pcl::SampleConsensusModelCylinder::optimizeModelCoefficients] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
264 if (inliers.empty ())
266 PCL_DEBUG (
"[pcl::SampleConsensusModelCylinder:optimizeModelCoefficients] Inliers vector empty! Returning the same coefficients.\n");
270 tmp_inliers_ = &inliers;
272 OptimizationFunctor functor (static_cast<int> (inliers.size ()),
this);
273 Eigen::NumericalDiff<OptimizationFunctor > num_diff (functor);
274 Eigen::LevenbergMarquardt<Eigen::NumericalDiff<OptimizationFunctor>,
float> lm (num_diff);
275 int info = lm.minimize (optimized_coefficients);
278 PCL_DEBUG (
"[pcl::SampleConsensusModelCylinder::optimizeModelCoefficients] LM solver finished with exit code %i, having a residual norm of %g. \nInitial solution: %g %g %g %g %g %g %g \nFinal solution: %g %g %g %g %g %g %g\n",
279 info, lm.fvec.norm (), model_coefficients[0], model_coefficients[1], model_coefficients[2], model_coefficients[3],
280 model_coefficients[4], model_coefficients[5], model_coefficients[6], optimized_coefficients[0], optimized_coefficients[1], optimized_coefficients[2], optimized_coefficients[3], optimized_coefficients[4], optimized_coefficients[5], optimized_coefficients[6]);
282 Eigen::Vector3f line_dir (optimized_coefficients[3], optimized_coefficients[4], optimized_coefficients[5]);
283 line_dir.normalize ();
284 optimized_coefficients[3] = line_dir[0];
285 optimized_coefficients[4] = line_dir[1];
286 optimized_coefficients[5] = line_dir[2];
290 template <
typename Po
intT,
typename Po
intNT>
void
292 const std::vector<int> &inliers,
const Eigen::VectorXf &model_coefficients,
PointCloud &projected_points,
bool copy_data_fields)
295 if (model_coefficients.size () != 7)
297 PCL_ERROR (
"[pcl::SampleConsensusModelCylinder::projectPoints] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
301 projected_points.
header = input_->header;
302 projected_points.
is_dense = input_->is_dense;
304 Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
305 Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
306 float ptdotdir = line_pt.dot (line_dir);
307 float dirdotdir = 1.0f / line_dir.dot (line_dir);
310 if (copy_data_fields)
313 projected_points.
points.resize (input_->points.size ());
314 projected_points.
width = input_->width;
315 projected_points.
height = input_->height;
319 for (
size_t i = 0; i < projected_points.
points.size (); ++i)
324 for (
size_t i = 0; i < inliers.size (); ++i)
326 Eigen::Vector4f p (input_->points[inliers[i]].x,
327 input_->points[inliers[i]].y,
328 input_->points[inliers[i]].z,
331 float k = (p.dot (line_dir) - ptdotdir) * dirdotdir;
334 pp = line_pt + k * line_dir;
336 Eigen::Vector4f dir = p - pp;
340 pp += dir * model_coefficients[6];
346 projected_points.
points.resize (inliers.size ());
347 projected_points.
width =
static_cast<uint32_t
> (inliers.size ());
348 projected_points.
height = 1;
352 for (
size_t i = 0; i < inliers.size (); ++i)
357 for (
size_t i = 0; i < inliers.size (); ++i)
362 float k = (p.dot (line_dir) - ptdotdir) * dirdotdir;
364 pp = line_pt + k * line_dir;
366 Eigen::Vector4f dir = p - pp;
370 pp += dir * model_coefficients[6];
376 template <
typename Po
intT,
typename Po
intNT>
bool
378 const std::set<int> &indices,
const Eigen::VectorXf &model_coefficients,
const double threshold)
381 if (model_coefficients.size () != 7)
383 PCL_ERROR (
"[pcl::SampleConsensusModelCylinder::doSamplesVerifyModel] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
387 for (std::set<int>::const_iterator it = indices.begin (); it != indices.end (); ++it)
392 Eigen::Vector4f pt (input_->points[*it].x, input_->points[*it].y, input_->points[*it].z, 0);
393 if (fabs (pointToLineDistance (pt, model_coefficients) - model_coefficients[6]) > threshold)
401 template <
typename Po
intT,
typename Po
intNT>
double
403 const Eigen::Vector4f &pt,
const Eigen::VectorXf &model_coefficients)
405 Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
406 Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
411 template <
typename Po
intT,
typename Po
intNT>
void
413 const Eigen::Vector4f &pt,
const Eigen::VectorXf &model_coefficients, Eigen::Vector4f &pt_proj)
415 Eigen::Vector4f line_pt (model_coefficients[0], model_coefficients[1], model_coefficients[2], 0);
416 Eigen::Vector4f line_dir (model_coefficients[3], model_coefficients[4], model_coefficients[5], 0);
418 float k = (pt.dot (line_dir) - line_pt.dot (line_dir)) * line_dir.dot (line_dir);
419 pt_proj = line_pt + k * line_dir;
421 Eigen::Vector4f dir = pt - pt_proj;
425 pt_proj += dir * model_coefficients[6];
429 template <
typename Po
intT,
typename Po
intNT>
bool
433 if (model_coefficients.size () != 7)
435 PCL_ERROR (
"[pcl::SampleConsensusModelCylinder::isModelValid] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
440 if (eps_angle_ > 0.0)
443 Eigen::Vector4f coeff;
444 coeff[0] = model_coefficients[3];
445 coeff[1] = model_coefficients[4];
446 coeff[2] = model_coefficients[5];
449 Eigen::Vector4f axis (axis_[0], axis_[1], axis_[2], 0);
450 double angle_diff = fabs (
getAngle3D (axis, coeff));
451 angle_diff = (std::min) (angle_diff, M_PI - angle_diff);
453 if (angle_diff > eps_angle_)
457 if (radius_min_ != -std::numeric_limits<double>::max() && model_coefficients[6] < radius_min_)
459 if (radius_max_ != std::numeric_limits<double>::max() && model_coefficients[6] > radius_max_)
465 #define PCL_INSTANTIATE_SampleConsensusModelCylinder(PointT, PointNT) template class PCL_EXPORTS pcl::SampleConsensusModelCylinder<PointT, PointNT>;
467 #endif // PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_CYLINDER_H_