Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sac_model_sphere.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2009, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id: sac_model_sphere.hpp 6144 2012-07-04 22:06:28Z rusu $
35  *
36  */
37 
38 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_SPHERE_H_
39 #define PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_SPHERE_H_
40 
42 #include <unsupported/Eigen/NonLinearOptimization>
43 
45 template <typename PointT> bool
46 pcl::SampleConsensusModelSphere<PointT>::isSampleGood (const std::vector<int> &) const
47 {
48  return (true);
49 }
50 
52 template <typename PointT> bool
54  const std::vector<int> &samples, Eigen::VectorXf &model_coefficients)
55 {
56  // Need 4 samples
57  if (samples.size () != 4)
58  {
59  PCL_ERROR ("[pcl::SampleConsensusModelSphere::computeModelCoefficients] Invalid set of samples given (%zu)!\n", samples.size ());
60  return (false);
61  }
62 
63  Eigen::Matrix4f temp;
64  for (int i = 0; i < 4; i++)
65  {
66  temp (i, 0) = input_->points[samples[i]].x;
67  temp (i, 1) = input_->points[samples[i]].y;
68  temp (i, 2) = input_->points[samples[i]].z;
69  temp (i, 3) = 1;
70  }
71  float m11 = temp.determinant ();
72  if (m11 == 0)
73  return (false); // the points don't define a sphere!
74 
75  for (int i = 0; i < 4; ++i)
76  temp (i, 0) = (input_->points[samples[i]].x) * (input_->points[samples[i]].x) +
77  (input_->points[samples[i]].y) * (input_->points[samples[i]].y) +
78  (input_->points[samples[i]].z) * (input_->points[samples[i]].z);
79  float m12 = temp.determinant ();
80 
81  for (int i = 0; i < 4; ++i)
82  {
83  temp (i, 1) = temp (i, 0);
84  temp (i, 0) = input_->points[samples[i]].x;
85  }
86  float m13 = temp.determinant ();
87 
88  for (int i = 0; i < 4; ++i)
89  {
90  temp (i, 2) = temp (i, 1);
91  temp (i, 1) = input_->points[samples[i]].y;
92  }
93  float m14 = temp.determinant ();
94 
95  for (int i = 0; i < 4; ++i)
96  {
97  temp (i, 0) = temp (i, 2);
98  temp (i, 1) = input_->points[samples[i]].x;
99  temp (i, 2) = input_->points[samples[i]].y;
100  temp (i, 3) = input_->points[samples[i]].z;
101  }
102  float m15 = temp.determinant ();
103 
104  // Center (x , y, z)
105  model_coefficients.resize (4);
106  model_coefficients[0] = 0.5f * m12 / m11;
107  model_coefficients[1] = 0.5f * m13 / m11;
108  model_coefficients[2] = 0.5f * m14 / m11;
109  // Radius
110  model_coefficients[3] = sqrtf (
111  model_coefficients[0] * model_coefficients[0] +
112  model_coefficients[1] * model_coefficients[1] +
113  model_coefficients[2] * model_coefficients[2] - m15 / m11);
114 
115  return (true);
116 }
117 
119 template <typename PointT> void
121  const Eigen::VectorXf &model_coefficients, std::vector<double> &distances)
122 {
123  // Check if the model is valid given the user constraints
124  if (!isModelValid (model_coefficients))
125  {
126  distances.clear ();
127  return;
128  }
129  distances.resize (indices_->size ());
130 
131  // Iterate through the 3d points and calculate the distances from them to the sphere
132  for (size_t i = 0; i < indices_->size (); ++i)
133  // Calculate the distance from the point to the sphere as the difference between
134  //dist(point,sphere_origin) and sphere_radius
135  distances[i] = fabs (sqrtf (
136  ( input_->points[(*indices_)[i]].x - model_coefficients[0] ) *
137  ( input_->points[(*indices_)[i]].x - model_coefficients[0] ) +
138 
139  ( input_->points[(*indices_)[i]].y - model_coefficients[1] ) *
140  ( input_->points[(*indices_)[i]].y - model_coefficients[1] ) +
141 
142  ( input_->points[(*indices_)[i]].z - model_coefficients[2] ) *
143  ( input_->points[(*indices_)[i]].z - model_coefficients[2] )
144  ) - model_coefficients[3]);
145 }
146 
148 template <typename PointT> void
150  const Eigen::VectorXf &model_coefficients, const double threshold, std::vector<int> &inliers)
151 {
152  // Check if the model is valid given the user constraints
153  if (!isModelValid (model_coefficients))
154  {
155  inliers.clear ();
156  return;
157  }
158 
159  int nr_p = 0;
160  inliers.resize (indices_->size ());
161 
162  // Iterate through the 3d points and calculate the distances from them to the sphere
163  for (size_t i = 0; i < indices_->size (); ++i)
164  {
165  // Calculate the distance from the point to the sphere as the difference between
166  // dist(point,sphere_origin) and sphere_radius
167  if (fabs (sqrtf (
168  ( input_->points[(*indices_)[i]].x - model_coefficients[0] ) *
169  ( input_->points[(*indices_)[i]].x - model_coefficients[0] ) +
170 
171  ( input_->points[(*indices_)[i]].y - model_coefficients[1] ) *
172  ( input_->points[(*indices_)[i]].y - model_coefficients[1] ) +
173 
174  ( input_->points[(*indices_)[i]].z - model_coefficients[2] ) *
175  ( input_->points[(*indices_)[i]].z - model_coefficients[2] )
176  ) - model_coefficients[3]) < threshold)
177  {
178  // Returns the indices of the points whose distances are smaller than the threshold
179  inliers[nr_p] = (*indices_)[i];
180  nr_p++;
181  }
182  }
183  inliers.resize (nr_p);
184 }
185 
187 template <typename PointT> int
189  const Eigen::VectorXf &model_coefficients, const double threshold)
190 {
191  // Check if the model is valid given the user constraints
192  if (!isModelValid (model_coefficients))
193  return (0);
194 
195  int nr_p = 0;
196 
197  // Iterate through the 3d points and calculate the distances from them to the sphere
198  for (size_t i = 0; i < indices_->size (); ++i)
199  {
200  // Calculate the distance from the point to the sphere as the difference between
201  // dist(point,sphere_origin) and sphere_radius
202  if (fabs (sqrtf (
203  ( input_->points[(*indices_)[i]].x - model_coefficients[0] ) *
204  ( input_->points[(*indices_)[i]].x - model_coefficients[0] ) +
205 
206  ( input_->points[(*indices_)[i]].y - model_coefficients[1] ) *
207  ( input_->points[(*indices_)[i]].y - model_coefficients[1] ) +
208 
209  ( input_->points[(*indices_)[i]].z - model_coefficients[2] ) *
210  ( input_->points[(*indices_)[i]].z - model_coefficients[2] )
211  ) - model_coefficients[3]) < threshold)
212  nr_p++;
213  }
214  return (nr_p);
215 }
216 
218 template <typename PointT> void
220  const std::vector<int> &inliers, const Eigen::VectorXf &model_coefficients, Eigen::VectorXf &optimized_coefficients)
221 {
222  optimized_coefficients = model_coefficients;
223 
224  // Needs a set of valid model coefficients
225  if (model_coefficients.size () != 4)
226  {
227  PCL_ERROR ("[pcl::SampleConsensusModelSphere::optimizeModelCoefficients] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
228  return;
229  }
230 
231  // Need at least 4 samples
232  if (inliers.size () <= 4)
233  {
234  PCL_ERROR ("[pcl::SampleConsensusModelSphere::optimizeModelCoefficients] Not enough inliers found to support a model (%zu)! Returning the same coefficients.\n", inliers.size ());
235  return;
236  }
237 
238  tmp_inliers_ = &inliers;
239 
240  OptimizationFunctor functor (static_cast<int> (inliers.size ()), this);
241  Eigen::NumericalDiff<OptimizationFunctor> num_diff (functor);
242  Eigen::LevenbergMarquardt<Eigen::NumericalDiff<OptimizationFunctor>, float> lm (num_diff);
243  int info = lm.minimize (optimized_coefficients);
244 
245  // Compute the L2 norm of the residuals
246  PCL_DEBUG ("[pcl::SampleConsensusModelSphere::optimizeModelCoefficients] LM solver finished with exit code %i, having a residual norm of %g. \nInitial solution: %g %g %g %g \nFinal solution: %g %g %g %g\n",
247  info, lm.fvec.norm (), model_coefficients[0], model_coefficients[1], model_coefficients[2], model_coefficients[3], optimized_coefficients[0], optimized_coefficients[1], optimized_coefficients[2], optimized_coefficients[3]);
248 }
249 
251 template <typename PointT> void
253  const std::vector<int> &, const Eigen::VectorXf &model_coefficients, PointCloud &projected_points, bool)
254 {
255  // Needs a valid model coefficients
256  if (model_coefficients.size () != 4)
257  {
258  PCL_ERROR ("[pcl::SampleConsensusModelSphere::projectPoints] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
259  return;
260  }
261 
262  // Allocate enough space and copy the basics
263  projected_points.points.resize (input_->points.size ());
264  projected_points.header = input_->header;
265  projected_points.width = input_->width;
266  projected_points.height = input_->height;
267  projected_points.is_dense = input_->is_dense;
268 
269  PCL_WARN ("[pcl::SampleConsensusModelSphere::projectPoints] Not implemented yet.\n");
270  projected_points.points = input_->points;
271 }
272 
274 template <typename PointT> bool
276  const std::set<int> &indices, const Eigen::VectorXf &model_coefficients, const double threshold)
277 {
278  // Needs a valid model coefficients
279  if (model_coefficients.size () != 4)
280  {
281  PCL_ERROR ("[pcl::SampleConsensusModelSphere::doSamplesVerifyModel] Invalid number of model coefficients given (%zu)!\n", model_coefficients.size ());
282  return (false);
283  }
284 
285  for (std::set<int>::const_iterator it = indices.begin (); it != indices.end (); ++it)
286  // Calculate the distance from the point to the sphere as the difference between
287  //dist(point,sphere_origin) and sphere_radius
288  if (fabs (sqrt (
289  ( input_->points[*it].x - model_coefficients[0] ) *
290  ( input_->points[*it].x - model_coefficients[0] ) +
291  ( input_->points[*it].y - model_coefficients[1] ) *
292  ( input_->points[*it].y - model_coefficients[1] ) +
293  ( input_->points[*it].z - model_coefficients[2] ) *
294  ( input_->points[*it].z - model_coefficients[2] )
295  ) - model_coefficients[3]) > threshold)
296  return (false);
297 
298  return (true);
299 }
300 
301 #define PCL_INSTANTIATE_SampleConsensusModelSphere(T) template class PCL_EXPORTS pcl::SampleConsensusModelSphere<T>;
302 
303 #endif // PCL_SAMPLE_CONSENSUS_IMPL_SAC_MODEL_SPHERE_H_
304