sac_model_line.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 
00036 #include <door_handle_detector/sample_consensus/sac_model_line.h>
00037 #include <door_handle_detector/geometry/point.h>
00038 #include <door_handle_detector/geometry/nearest.h>
00039 #include <Eigen/Eigenvalues>
00040 
00041 namespace sample_consensus
00042 {
00044 
00049   void
00050     SACModelLine::getSamples (int &iterations, std::vector<int> &samples)
00051   {
00052     samples.resize (2);
00053     double trand = indices_.size () / (RAND_MAX + 1.0);
00054 
00055     // Get a random number between 1 and max_indices
00056     int idx = (int)(rand () * trand);
00057     // Get the index
00058     samples[0] = indices_.at (idx);
00059 
00060     // Get a second point which is different than the first
00061     int iter = 0;
00062     do
00063     {
00064       idx = (int)(rand () * trand);
00065       samples[1] = indices_.at (idx);
00066       iter++;
00067 
00068       if (iter > MAX_ITERATIONS_UNIQUE)
00069       {
00070         ROS_WARN ("[SACModelLine::getSamples] WARNING: Could not select 2 unique points in %d iterations!", MAX_ITERATIONS_UNIQUE);
00071         break;
00072       }
00073       iterations++;
00074     } while (samples[1] == samples[0]);
00075     iterations--;
00076     return;
00077   }
00078 
00080 
00087   void
00088     SACModelLine::selectWithinDistance (const std::vector<double> &model_coefficients, double threshold, std::vector<int> &inliers)
00089   {
00090     double sqr_threshold = threshold * threshold;
00091 
00092     int nr_p = 0;
00093     inliers.resize (indices_.size ());
00094 
00095     // Obtain the line direction
00096     geometry_msgs::Point32 p3, p4;
00097     p3.x = model_coefficients.at (3) - model_coefficients.at (0);
00098     p3.y = model_coefficients.at (4) - model_coefficients.at (1);
00099     p3.z = model_coefficients.at (5) - model_coefficients.at (2);
00100 
00101     // Iterate through the 3d points and calculate the distances from them to the plane
00102     for (unsigned int i = 0; i < indices_.size (); i++)
00103     {
00104       // Calculate the distance from the point to the line
00105       // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
00106       // P1, P2 = line points, P0 = query point
00107       // P1P2 = <x2-x1, y2-y1, z2-z1> = <x3, y3, z3>
00108       // P1P0 = < x-x1,  y-y1, z-z1 > = <x4, y4, z4>
00109       // P1P2 x P1P0 = < y3*z4 - z3*y4, -(x3*z4 - x4*z3), x3*y4 - x4*y3 >
00110       //             = < (y2-y1)*(z-z1) - (z2-z1)*(y-y1), -[(x2-x1)*(z-z1) - (x-x1)*(z2-z1)], (x2-x1)*(y-y1) - (x-x1)*(y2-y1) >
00111       p4.x = model_coefficients.at (3) - cloud_->points.at (indices_.at (i)).x;
00112       p4.y = model_coefficients.at (4) - cloud_->points.at (indices_.at (i)).y;
00113       p4.z = model_coefficients.at (5) - cloud_->points.at (indices_.at (i)).z;
00114 
00115       // P1P2 = sqrt (x3^2 + y3^2 + z3^2)
00116       // a = sqrt [(y3*z4 - z3*y4)^2 + (x3*z4 - x4*z3)^2 + (x3*y4 - x4*y3)^2]
00117       //double distance = SQR_NORM (cANN::cross (p4, p3)) / SQR_NORM (p3);
00118       geometry_msgs::Point32 c = cloud_geometry::cross (p4, p3);
00119       double sqr_distance = (c.x * c.x + c.y * c.y + c.z * c.z) / (p3.x * p3.x + p3.y * p3.y + p3.z * p3.z);
00120 
00121       if (sqr_distance < sqr_threshold)
00122       {
00123         // Returns the indices of the points whose squared distances are smaller than the threshold
00124         inliers[nr_p] = indices_[i];
00125         nr_p++;
00126       }
00127     }
00128     inliers.resize (nr_p);
00129     return;
00130   }
00131 
00133 
00137   void
00138     SACModelLine::getDistancesToModel (const std::vector<double> &model_coefficients, std::vector<double> &distances)
00139   {
00140     distances.resize (indices_.size ());
00141 
00142     // Obtain the line direction
00143     geometry_msgs::Point32 p3, p4;
00144     p3.x = model_coefficients.at (3) - model_coefficients.at (0);
00145     p3.y = model_coefficients.at (4) - model_coefficients.at (1);
00146     p3.z = model_coefficients.at (5) - model_coefficients.at (2);
00147 
00148     // Iterate through the 3d points and calculate the distances from them to the plane
00149     for (unsigned int i = 0; i < indices_.size (); i++)
00150     {
00151       // Calculate the distance from the point to the line
00152       // D = ||(P2-P1) x (P1-P0)|| / ||P2-P1|| = norm (cross (p2-p1, p2-p0)) / norm(p2-p1)
00153       p4.x = model_coefficients.at (3) - cloud_->points.at (indices_.at (i)).x;
00154       p4.y = model_coefficients.at (4) - cloud_->points.at (indices_.at (i)).y;
00155       p4.z = model_coefficients.at (5) - cloud_->points.at (indices_.at (i)).z;
00156 
00157       geometry_msgs::Point32 c = cloud_geometry::cross (p4, p3);
00158       distances[i] = sqrt (c.x * c.x + c.y * c.y + c.z * c.z) / (p3.x * p3.x + p3.y * p3.y + p3.z * p3.z);
00159     }
00160     return;
00161   }
00162 
00164 
00169   void
00170     SACModelLine::projectPoints (const std::vector<int> &inliers, const std::vector<double> &model_coefficients,
00171                                  sensor_msgs::PointCloud &projected_points)
00172   {
00173     // Allocate enough space
00174     projected_points.points.resize (inliers.size ());
00175     projected_points.channels.resize (cloud_->channels.size ());
00176 
00177     // Create the channels
00178     for (unsigned int d = 0; d < projected_points.channels.size (); d++)
00179     {
00180       projected_points.channels[d].name = cloud_->channels[d].name;
00181       projected_points.channels[d].values.resize (inliers.size ());
00182     }
00183 
00184     // Compute the line direction (P2 - P1)
00185     geometry_msgs::Point32 p21;
00186     p21.x = model_coefficients.at (3) - model_coefficients.at (0);
00187     p21.y = model_coefficients.at (4) - model_coefficients.at (1);
00188     p21.z = model_coefficients.at (5) - model_coefficients.at (2);
00189 
00190     // Iterate through the 3d points and calculate the distances from them to the line
00191     for (unsigned int i = 0; i < inliers.size (); i++)
00192     {
00193       // double k = (DOT_PROD_3D (points[i], p21) - dotA_B) / dotB_B;
00194       double k = ( cloud_->points.at (inliers.at (i)).x * p21.x + cloud_->points.at (inliers.at (i)).y * p21.y + cloud_->points.at (inliers.at (i)).z * p21.z -
00195                    (model_coefficients_[0] * p21.x + model_coefficients_[1] * p21.y + model_coefficients_[2] * p21.z)
00196                  ) / (p21.x * p21.x + p21.y * p21.y + p21.z * p21.z);
00197       // Calculate the projection of the point on the line (pointProj = A + k * B)
00198       projected_points.points[i].x = model_coefficients_.at (0) + k * p21.x;
00199       projected_points.points[i].y = model_coefficients_.at (1) + k * p21.y;
00200       projected_points.points[i].z = model_coefficients_.at (2) + k * p21.z;
00201       // Copy the other attributes
00202       for (unsigned int d = 0; d < projected_points.channels.size (); d++)
00203         projected_points.channels[d].values[i] = cloud_->channels[d].values[inliers.at (i)];
00204     }
00205   }
00206 
00208 
00212   void
00213     SACModelLine::projectPointsInPlace (const std::vector<int> &inliers, const std::vector<double> &model_coefficients)
00214   {
00215     // Compute the line direction (P2 - P1)
00216     geometry_msgs::Point32 p21;
00217     p21.x = model_coefficients.at (3) - model_coefficients.at (0);
00218     p21.y = model_coefficients.at (4) - model_coefficients.at (1);
00219     p21.z = model_coefficients.at (5) - model_coefficients.at (2);
00220 
00221     // Iterate through the 3d points and calculate the distances from them to the line
00222     for (unsigned int i = 0; i < inliers.size (); i++)
00223     {
00224       // double k = (DOT_PROD_3D (points[i], p21) - dotA_B) / dotB_B;
00225       double k = ( cloud_->points.at (inliers.at (i)).x * p21.x + cloud_->points.at (inliers.at (i)).y * p21.y + cloud_->points.at (inliers.at (i)).z * p21.z -
00226                    (model_coefficients_[0] * p21.x + model_coefficients_[1] * p21.y + model_coefficients_[2] * p21.z)
00227                  ) / (p21.x * p21.x + p21.y * p21.y + p21.z * p21.z);
00228       // Calculate the projection of the point on the line (pointProj = A + k * B)
00229       cloud_->points.at (inliers.at (i)).x = model_coefficients_.at (0) + k * p21.x;
00230       cloud_->points.at (inliers.at (i)).y = model_coefficients_.at (1) + k * p21.y;
00231       cloud_->points.at (inliers.at (i)).z = model_coefficients_.at (2) + k * p21.z;
00232     }
00233   }
00234 
00236 
00241   bool
00242     SACModelLine::computeModelCoefficients (const std::vector<int> &samples)
00243   {
00244     model_coefficients_.resize (6);
00245     model_coefficients_[0] = cloud_->points.at (samples.at (0)).x;
00246     model_coefficients_[1] = cloud_->points.at (samples.at (0)).y;
00247     model_coefficients_[2] = cloud_->points.at (samples.at (0)).z;
00248     model_coefficients_[3] = cloud_->points.at (samples.at (1)).x;
00249     model_coefficients_[4] = cloud_->points.at (samples.at (1)).y;
00250     model_coefficients_[5] = cloud_->points.at (samples.at (1)).z;
00251 
00252     return (true);
00253   }
00254 
00256 
00261   void
00262     SACModelLine::refitModel (const std::vector<int> &inliers, std::vector<double> &refit_coefficients)
00263   {
00264     if (inliers.size () == 0)
00265     {
00266       ROS_ERROR ("[SACModelLine::RefitModel] Cannot re-fit 0 inliers!");
00267       refit_coefficients = model_coefficients_;
00268       return;
00269     }
00270 
00271     refit_coefficients.resize (6);
00272 
00273     // Compute the centroid of the samples
00274     geometry_msgs::Point32 centroid;
00275     // Compute the 3x3 covariance matrix
00276     Eigen::Matrix3d covariance_matrix;
00277     cloud_geometry::nearest::computeCovarianceMatrix (*cloud_, inliers, covariance_matrix, centroid);
00278 
00279     refit_coefficients[0] = centroid.x;
00280     refit_coefficients[1] = centroid.y;
00281     refit_coefficients[2] = centroid.z;
00282 
00283     // Extract the eigenvalues and eigenvectors
00284     //cloud_geometry::eigen_cov (covariance_matrix, eigen_values, eigen_vectors);
00285     Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> ei_symm (covariance_matrix);
00286     Eigen::Vector3d eigen_values  = ei_symm.eigenvalues ();
00287     Eigen::Matrix3d eigen_vectors = ei_symm.eigenvectors ();
00288 
00289     refit_coefficients[3] = eigen_vectors (0, 2) + refit_coefficients[0];
00290     refit_coefficients[4] = eigen_vectors (1, 2) + refit_coefficients[1];
00291     refit_coefficients[5] = eigen_vectors (2, 2) + refit_coefficients[2];
00292   }
00293 
00295 
00299   bool
00300     SACModelLine::doSamplesVerifyModel (const std::set<int> &indices, double threshold)
00301   {
00302     double sqr_threshold = threshold * threshold;
00303     for (std::set<int>::iterator it = indices.begin (); it != indices.end (); ++it)
00304     {
00305       geometry_msgs::Point32 p3, p4;
00306       p3.x = model_coefficients_.at (3) - model_coefficients_.at (0);
00307       p3.y = model_coefficients_.at (4) - model_coefficients_.at (1);
00308       p3.z = model_coefficients_.at (5) - model_coefficients_.at (2);
00309 
00310       p4.x = model_coefficients_.at (3) - cloud_->points.at (*it).x;
00311       p4.y = model_coefficients_.at (4) - cloud_->points.at (*it).y;
00312       p4.z = model_coefficients_.at (5) - cloud_->points.at (*it).z;
00313 
00314       geometry_msgs::Point32 c = cloud_geometry::cross (p4, p3);
00315       double sqr_distance = (c.x * c.x + c.y * c.y + c.z * c.z) / (p3.x * p3.x + p3.y * p3.y + p3.z * p3.z);
00316 
00317       if (sqr_distance < sqr_threshold)
00318         return (false);
00319     }
00320     return (true);
00321   }
00322 }


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