sac_model_circle.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Radu Bogdan Rusu <rusu -=- cs.tum.edu>
00003  *
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  *     * Redistributions of source code must retain the above copyright
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright
00012  *       notice, this list of conditions and the following disclaimer in the
00013  *       documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00025  * POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  * $Id$
00028  *
00029  */
00030 
00033 #include <door_handle_detector/sample_consensus/sac_model_circle.h>
00034 #include <door_handle_detector/geometry/nearest.h>
00035 
00036 #include <cminpack.h>
00037 
00038 #define SQR(a) ((a)*(a))
00039 
00040 namespace sample_consensus
00041 {
00043 
00048   void
00049     SACModelCircle2D::getSamples (int &iterations, std::vector<int> &samples)
00050   {
00051     samples.resize (3);
00052     double trand = indices_.size () / (RAND_MAX + 1.0);
00053 
00054     // Get a random number between 1 and max_indices
00055     int idx = (int)(rand () * trand);
00056     // Get the index
00057     samples[0] = indices_.at (idx);
00058 
00059     // Get a second point which is different than the first
00060     do
00061     {
00062       idx = (int)(rand () * trand);
00063       samples[1] = indices_.at (idx);
00064       iterations++;
00065     } while (samples[1] == samples[0]);
00066     iterations--;
00067 
00068     double Dx1, Dy1, Dz1, Dx2, Dy2, Dz2, Dy1Dy2;
00069     // Compute the segment values (in 3d) between XY
00070     Dx1 = cloud_->points[samples[1]].x - cloud_->points[samples[0]].x;
00071     Dy1 = cloud_->points[samples[1]].y - cloud_->points[samples[0]].y;
00072     Dz1 = cloud_->points[samples[1]].z - cloud_->points[samples[0]].z;
00073 
00074     int iter = 0;
00075     do
00076     {
00077       // Get the third point, different from the first two
00078       do
00079       {
00080         idx = (int)(rand () * trand);
00081         samples[2] = indices_.at (idx);
00082         iterations++;
00083       } while ( (samples[2] == samples[1]) || (samples[2] == samples[0]) );
00084       iterations--;
00085 
00086       // Compute the segment values (in 3d) between XZ
00087       Dx2 = cloud_->points[samples[2]].x - cloud_->points[samples[0]].x;
00088       Dy2 = cloud_->points[samples[2]].y - cloud_->points[samples[0]].y;
00089       Dz2 = cloud_->points[samples[2]].z - cloud_->points[samples[0]].z;
00090 
00091       Dy1Dy2 = Dy1 / Dy2;
00092       iter++;
00093 
00094       if (iter > MAX_ITERATIONS_COLLINEAR )
00095       {
00096         ROS_WARN ("[SACModelCircle2D::getSamples] WARNING: Could not select 3 non collinear points in %d iterations!",  MAX_ITERATIONS_COLLINEAR);
00097         break;
00098       }
00099       iterations++;
00100     }
00101     // Use Zoli's method for collinearity check
00102     while (((Dx1 / Dx2) == Dy1Dy2) && (Dy1Dy2 == (Dz1 / Dz2)));
00103     iterations--;
00104 
00105     return;
00106   }
00107 
00109 
00116   void
00117     SACModelCircle2D::selectWithinDistance (const std::vector<double> &model_coefficients, double threshold, std::vector<int> &inliers)
00118   {
00119     int nr_p = 0;
00120     inliers.resize (indices_.size ());
00121 
00122     // Iterate through the 3d points and calculate the distances from them to the circle
00123     for (unsigned int i = 0; i < indices_.size (); i++)
00124     {
00125       // Calculate the distance from the point to the circle as the difference between
00126       //dist(point,circle_origin) and circle_radius
00127       double distance_to_circle = fabs (sqrt (
00128                                               ( cloud_->points.at (indices_[i]).x - model_coefficients.at (0) ) *
00129                                               ( cloud_->points.at (indices_[i]).x - model_coefficients.at (0) ) +
00130 
00131                                               ( cloud_->points.at (indices_[i]).y - model_coefficients.at (1) ) *
00132                                               ( cloud_->points.at (indices_[i]).y - model_coefficients.at (1) )
00133                                              ) - model_coefficients.at (2));
00134       if (distance_to_circle < threshold)
00135       {
00136         // Returns the indices of the points whose distances are smaller than the threshold
00137         inliers[nr_p] = indices_[i];
00138         nr_p++;
00139       }
00140     }
00141     inliers.resize (nr_p);
00142     return;
00143   }
00144 
00146 
00150   void
00151     SACModelCircle2D::getDistancesToModel (const std::vector<double> &model_coefficients, std::vector<double> &distances)
00152   {
00153     distances.resize (indices_.size ());
00154 
00155     // Iterate through the 3d points and calculate the distances from them to the circle
00156     for (unsigned int i = 0; i < indices_.size (); i++)
00157       // Calculate the distance from the point to the circle as the difference between
00158       //dist(point,circle_origin) and circle_radius
00159       distances[i] = fabs (sqrt (
00160                                  ( cloud_->points.at (indices_[i]).x - model_coefficients.at (0) ) *
00161                                  ( cloud_->points.at (indices_[i]).x - model_coefficients.at (0) ) +
00162 
00163                                  ( cloud_->points.at (indices_[i]).y - model_coefficients.at (1) ) *
00164                                  ( cloud_->points.at (indices_[i]).y - model_coefficients.at (1) )
00165                                 ) - model_coefficients.at (2));
00166     return;
00167   }
00168 
00170 
00176   void
00177     SACModelCircle2D::projectPoints (const std::vector<int> &inliers, const std::vector<double> &model_coefficients,
00178                                      sensor_msgs::PointCloud &projected_points)
00179   {
00180 //    std::cerr << "[SACModelCircle2D::projecPoints] Not implemented yet." << std::endl;
00181     projected_points = *cloud_;
00182 
00183         double cx = model_coefficients[0];
00184         double cy = model_coefficients[1];
00185         double r =  model_coefficients[2];
00186         for(size_t i=0;i<cloud_->get_points_size();i++) {
00187                 double dx = cloud_->points[i].x - cx;
00188                 double dy = cloud_->points[i].y - cy;
00189                 double a = sqrt( SQR(r) / ( SQR(dx) + SQR(dy) ));
00190                 projected_points.points[i].x = a*dx + cx;
00191                 projected_points.points[i].y = a*dy + cy;
00192         }
00193   }
00194 
00196 
00201   void
00202     SACModelCircle2D::projectPointsInPlace (const std::vector<int> &inliers, const std::vector<double> &model_coefficients)
00203   {
00204     std::cerr << "[SACModelCircle2D::projecPointsInPlace] Not implemented yet." << std::endl;
00205   }
00206 
00208 
00212   bool
00213     SACModelCircle2D::computeModelCoefficients (const std::vector<int> &samples)
00214   {
00215     model_coefficients_.resize (3);
00216 
00217     geometry_msgs::Point32 u, v, m;
00218     u.x = ( cloud_->points.at (samples.at (0)).x + cloud_->points.at (samples.at (1)).x ) / 2;
00219     u.y = ( cloud_->points.at (samples.at (1)).x + cloud_->points.at (samples.at (2)).x ) / 2;
00220 
00221     v.x = ( cloud_->points.at (samples.at (0)).y + cloud_->points.at (samples.at (1)).y ) / 2;
00222     v.y = ( cloud_->points.at (samples.at (1)).y + cloud_->points.at (samples.at (2)).y ) / 2;
00223 
00224     m.x = -( cloud_->points.at (samples.at (1)).x - cloud_->points.at (samples.at (0)).x ) /
00225            ( cloud_->points.at (samples.at (1)).y - cloud_->points.at (samples.at (0)).y );
00226     m.y = -( cloud_->points.at (samples.at (2)).x - cloud_->points.at (samples.at (1)).x ) /
00227            ( cloud_->points.at (samples.at (2)).y - cloud_->points.at (samples.at (1)).y );
00228 
00229     // Center (x, y)
00230     model_coefficients_[0] = (m.x * u.x -  m.y * u.y  - (v.x - v.y) )           / (m.x - m.y);
00231     model_coefficients_[1] = (m.x * m.y * (u.x - u.y) +  m.x * v.y - m.y * v.x) / (m.x - m.y);
00232 
00233     // Radius
00234     model_coefficients_[2] = sqrt (
00235                                    ( model_coefficients_[0] - cloud_->points.at (samples.at (0)).x ) *
00236                                    ( model_coefficients_[0] - cloud_->points.at (samples.at (0)).x ) +
00237 
00238                                    ( model_coefficients_[1] - cloud_->points.at (samples.at (0)).y ) *
00239                                    ( model_coefficients_[1] - cloud_->points.at (samples.at (0)).y )
00240                                   );
00241     return (true);
00242   }
00243 
00245 
00250   void
00251     SACModelCircle2D::refitModel (const std::vector<int> &inliers, std::vector<double> &refit_coefficients)
00252   {
00253     if (inliers.size () == 0)
00254     {
00255       ROS_ERROR ("[SACModelCircle2D::RefitModel] Cannot re-fit 0 inliers!");
00256       refit_coefficients = model_coefficients_;
00257       return;
00258     }
00259     if (model_coefficients_.size () == 0)
00260     {
00261       ROS_WARN ("[SACModelCircle2D::RefitModel] Initial model coefficients have not been estimated yet - proceeding without an initial solution!");
00262       best_inliers_ = indices_;
00263     }
00264 
00265     tmp_inliers_ = &inliers;
00266     
00267     int m = inliers.size ();
00268 
00269     double *fvec = new double[m];
00270 
00271     int n = 3;      // 3 unknowns
00272     int iwa[n];
00273 
00274     int lwa = m * n + 5 * n + m;
00275     double *wa = new double[lwa];
00276 
00277     // Set the initial solution
00278     double x[3] = {0.0, 0.0, 0.0};
00279     if ((int)model_coefficients_.size () == n)
00280       for (int d = 0; d < n; d++)
00281         x[d] = model_coefficients_.at (d);
00282 
00283     // Set tol to the square root of the machine. Unless high solutions are required, these are the recommended settings.
00284     double tol = sqrt (dpmpar (1));
00285 
00286     // Optimize using forward-difference approximation LM
00287     int info = lmdif1 (&sample_consensus::SACModelCircle2D::functionToOptimize, this, m, n, x, fvec, tol, iwa, wa, lwa);
00288 
00289     // Compute the L2 norm of the residuals
00290     ROS_DEBUG  ("LM solver finished with exit code %i, having a residual norm of %g. \nInitial solution: %g %g %g \nFinal solution: %g %g %g",
00291                 info, enorm (m, fvec), model_coefficients_.at (0), model_coefficients_.at (1), model_coefficients_.at (2), x[0], x[1], x[2]);
00292 
00293     refit_coefficients.resize (n);
00294     for (int d = 0; d < n; d++)
00295       refit_coefficients[d] = x[d];
00296 
00297     free (wa); free (fvec);
00298   }
00299 
00301 
00309   int
00310     SACModelCircle2D::functionToOptimize (void *p, int m, int n, const double *x, double *fvec, int iflag)
00311   {
00312     SACModelCircle2D *model = (SACModelCircle2D*)p;
00313 
00314     for (int i = 0; i < m; i ++)
00315     {
00316       // Compute the difference between the center of the circle and the datapoint X_i
00317       double xt = model->cloud_->points[model->tmp_inliers_->at (i)].x - x[0];
00318       double yt = model->cloud_->points[model->tmp_inliers_->at (i)].y - x[1];
00319 
00320       // g = sqrt ((x-a)^2 + (y-b)^2) - R
00321       fvec[i] = sqrt (xt * xt + yt * yt) - x[2];
00322     }
00323     return (0);
00324   }
00325 
00327 
00331   bool
00332     SACModelCircle2D::doSamplesVerifyModel (const std::set<int> &indices, double threshold)
00333   {
00334     // Iterate through the 3d points and calculate the distances from them to the circle
00335     for (std::set<int>::iterator it = indices.begin (); it != indices.end (); ++it)
00336     {
00337       // Calculate the distance from the point to the circle as the difference between
00338       //dist(point,circle_origin) and circle_radius
00339       double distance_to_circle = fabs (sqrt (
00340                                               ( cloud_->points.at (*it).x - model_coefficients_.at (0) ) *
00341                                               ( cloud_->points.at (*it).x - model_coefficients_.at (0) ) +
00342 
00343                                               ( cloud_->points.at (*it).y - model_coefficients_.at (1) ) *
00344                                               ( cloud_->points.at (*it).y - model_coefficients_.at (1) )
00345                                              ) - model_coefficients_.at (2));
00346       if (distance_to_circle > threshold)
00347         return (false);
00348     }
00349     return (true);
00350   }
00351 }


door_handle_detector
Author(s): Radu Bogdan Rusu, Marius
autogenerated on Wed Dec 11 2013 14:17:01