pcl_sac_model_orientation.hpp
Go to the documentation of this file.
00001 //#include <pcl_ias_sample_consensus/pcl_sac_model_orientation.h>
00002 //
00003 //namespace
00004 //{
00005 //  void
00006 //    SACModelOrientation::init (sensor_msgs::PointCloud *cloud)
00007 //  {
00008 //    // Locate channels with normals
00009 //    for (unsigned int d = 0; d < cloud->channels.size (); d++)
00010 //      if (cloud->channels[d].name == "nx")
00011 //      {
00012 //        nx_idx_ = d;
00013 //        break;
00014 //      }
00015 //    if (nx_idx_ == -1)
00016 //    {
00017 //      ROS_ERROR ("[SACModelOrientation] Provided point cloud does not have normals!");
00018 //      return;
00019 //    }
00020 //
00021 //    // Copy normals of points into a PCD -- not the most optimal way of creating the kd-tree, but the only one easily available as of this writing :)
00022 //    //normals_ = new sensor_msgs::PointCloud;
00023 //    normals_.points.resize (indices_.size ()); // we don't care about header and channels
00024 //    for (unsigned i = 0; i < normals_.points.size (); i++)
00025 //    {
00026 //      normals_.points[i].x = cloud->channels[nx_idx_+0].values[indices_[i]];
00027 //      normals_.points[i].y = cloud->channels[nx_idx_+1].values[indices_[i]];
00028 //      normals_.points[i].z = cloud->channels[nx_idx_+2].values[indices_[i]];
00029 //    }
00030 //
00031 //    // Create kd-tree
00032 //    kdtree_ = new cloud_kdtree::KdTreeANN (normals_);
00033 //  }
00034 
00035 //template<typename NormalT> void
00036 //    pcl::SACModelOrientation<NormalT>::getMinAndMax (boost::shared_ptr<pcl::PointCloud<PointT> > cloud, Eigen::VectorXf *model_coefficients, std::vector<int> *inliers, std::vector<int> &min_max_indices, std::vector<float> &min_max_distances)
00037 //  {
00038 //    // Initialize result vectors
00039 //    min_max_indices.resize (6);
00040 //    min_max_distances.resize (6);
00041 //    min_max_distances[0] = min_max_distances[2] = min_max_distances[4] = +DBL_MAX;
00042 //    min_max_distances[1] = min_max_distances[3] = min_max_distances[5] = -DBL_MAX;
00043 //
00044 //    // The 3 coordinate axes are nm, nc and axis_
00045 //    Eigen::Vector3f nm = Eigen::Vector3d::Map(&(*model_coefficients)[0]).cast<float> ();
00046 //    Eigen::Vector3f nc = axis_.cross (nm);
00047 //
00048 //    // Find minimum and maximum distances from origin along the three axes
00049 //    for (std::vector<int>::iterator it = inliers->begin (); it != inliers->end (); it++)
00050 //    //for (unsigned i = 0; i < inliers.size (); i++)
00051 //    {
00052 //      /// @NOTE inliers is a list of indices of the indices_ array!
00053 //      Eigen::Vector3f point (input_->points[(*indices_)[*it]].x, input_->points[(*indices_)[*it]].y, input_->points[(*indices_)[*it]].z);
00054 //      //Eigen::Vector3f point (cloud_->points[indices_[*it]].x - center.x, cloud_->points[indices_[*it]].y - center.y, cloud_->points[indices_[*it]].z - center.z);
00055 //      //Eigen::Vector3f point (cloud_->points[indices_[inliers[i]]].x, cloud_->points[indices_[inliers[i]]].y, cloud_->points[indices_[inliers[i]]].z);
00056 //      double dists[3];
00057 //      dists[0] = nm.dot(point);
00058 //      dists[1] = nc.dot(point);
00059 //      dists[2] = axis_.dot(point);
00060 //      for (int d=0; d<3; d++)
00061 //      {
00062 //        if (min_max_distances[2*d+0] > dists[d]) { min_max_distances[2*d+0] = dists[d]; min_max_indices[2*d+0] = *it; }
00063 //        if (min_max_distances[2*d+1] < dists[d]) { min_max_distances[2*d+1] = dists[d]; min_max_indices[2*d+1] = *it; }
00064 //      }
00065 //    }
00066 //  }
00067 
00068 template <typename NormalT> void
00069     pcl::SACModelOrientation<NormalT>::getSamples (int &iterations, std::vector<int> &samples)
00070   {
00071     // We're assuming that indices_ have already been set in the constructor
00072     ROS_ASSERT (indices_->size () != 0);
00073 
00075 
00076     // Get a random number between 0 and indices_.size ()
00077     samples.resize (1);
00078 
00079     // I don't care, but: http://www.thinkage.ca/english/gcos/expl/c/lib/rand.html
00080     while (indices_->size () <= (unsigned)(samples[0] = rand () / (RAND_MAX/indices_->size ())));
00081     //unsigned idx;// = (int)(rand () * indices_.size () / (RAND_MAX + 1.0));
00082     //while (indices_.size () <= (idx = rand () / (RAND_MAX/indices_.size ())));
00083     // Get the index
00084     //samples[0] = indices_.at (idx);
00085 
00086     // TODO: repeat this and test coefficients until ok? increase iterations?
00087   }
00088 
00089 template <typename NormalT> bool
00090    pcl::SACModelOrientation<NormalT>::computeModelCoefficients (const std::vector<int> &samples, Eigen::VectorXf &model_coefficients)
00091   {
00092     // Check whether the given index samples can form a valid model
00093     // compute the model coefficients from these samples
00094     // and store them internally in model_coefficients_
00095     model_coefficients.resize (4);
00096     //model_coefficients_[0] = cloud_->channels[nx_idx_+0].values[samples[0]];
00097     //model_coefficients_[1] = cloud_->channels[nx_idx_+1].values[samples[0]];
00098     //model_coefficients_[2] = cloud_->channels[nx_idx_+2].values[samples[0]];
00099     //model_coefficients_[0] = normals_.points[samples[0]].x;
00100     //model_coefficients_[1] = normals_.points[samples[0]].y;
00101     //model_coefficients_[2] = normals_.points[samples[0]].z;
00102     model_coefficients[0] = input_->points[samples[0]].normal[0];
00103     model_coefficients[1] = input_->points[samples[0]].normal[1];
00104     model_coefficients[2] = input_->points[samples[0]].normal[2];
00105     model_coefficients[3] = samples[0];
00106     return true; // return value not used anyways
00107   }
00108 
00109 template <typename NormalT> void
00110    pcl::SACModelOrientation<NormalT>::refitModel (const std::vector<int> &inliers, std::vector<double> &refit_coefficients)
00111   {
00112     // Compute average direction
00113     refit_coefficients.resize (4);
00114 
00115     // Coefficient[3] will hold the the source point's index
00116     if (inliers.size () == 0)
00117     {
00118       ROS_ERROR ("[SACModelOrientation] Can not re-fit 0 points! Returned -1 as source index (in refit_coefficients[3]).");
00119       refit_coefficients[3] = -1;
00120       return;
00121     }
00122     refit_coefficients[3] = inliers.at (0);
00123 
00124     //*
00125 
00126     // Get source and acceptable distance from it
00127     Eigen::Vector3f nm (input_->points[refit_coefficients[3]].normal[0], input_->points[refit_coefficients[3]].normal[1], input_.points[refit_coefficients[3]].normal[2]);
00128     double eps_angle = M_PI/6; // or use a user defined threshold (eps_angle_)?
00129     double radius = 2 * sin (eps_angle/2);
00130     double sqr_radius = radius*radius;
00131 
00132     // get local coordinate system from the axis
00133     //Eigen::Vector3f v = axis_.unitOrthogonal ();
00134     //Eigen::Vector3f u = axis_.cross (v);
00135 
00136     //Eigen::MatrixXf rotated_normals(inliers.size (), 3);
00137     Eigen::Vector3f sum_rotated_normals = Eigen::VectorXf::Zero(3);
00138 
00139     // Rotate all inliers onto the first direction and sum them up
00140     for (unsigned it = 0; it < inliers.size (); it++)
00141     //for (std::vector<int>::iterator it = inliers.begin (); it != inliers.end (); it++)
00142     {
00145       Eigen::Vector3f ni (input_->points[inliers[it]].normal[0], input_->points[inliers[it]].normal[1], input_->points[inliers[it]].normal[2]);
00146       //std::cerr << "inlier " << it << "/" << inliers[it] << ": " << ni.transpose () << std::endl;
00147       //Eigen::Vector3f ni2 = ni.cwise.square ();
00148       for (int i=0; i<4; i++)
00149       {
00150         // Find the orientation that is pointing in the same direction as the model
00151         if ((nm-ni).squaredNorm () < sqr_radius)
00152           break;
00153         ni = rotateAroundAxis (ni, axis_, M_PI/2);
00154         //std::cerr << i << ": " << ni.transpose () << std::endl;
00155       }
00156       sum_rotated_normals += ni;
00157     }
00158 
00159     // Compute average and normalize to get the final model
00160     sum_rotated_normals /= inliers.size ();
00161     sum_rotated_normals.normalize();
00162     refit_coefficients[0] = sum_rotated_normals[0];
00163     refit_coefficients[1] = sum_rotated_normals[1];
00164     refit_coefficients[2] = sum_rotated_normals[2];
00165 
00166     //*/
00167   }
00168 
00169 template <typename NormalT>  void
00170    pcl::SACModelOrientation<NormalT>::selectWithinDistance (const Eigen::VectorXf &model_coefficients, double threshold, std::vector<int> &inliers)
00171   {
00172     //std::cerr << model_coefficients[3] << ": " << model_coefficients[0] << " " << model_coefficients[1] << " " << model_coefficients[2] << " ";
00173 
00174     // accept only if model direction is perpendicular to axis_
00175     double cosine = axis_[0]*model_coefficients[0] + axis_[1]*model_coefficients[1] + axis_[2]*model_coefficients[2];
00176     if (cosine > 1) cosine = 1;
00177     if (cosine < -1) cosine = -1;
00178     //std::cerr << "angle difference = " << acos (cosine);
00179     if (fabs (acos (cosine) - M_PI/2) > threshold)
00180     {
00181       // this will make sure the model is not accepted
00182       inliers.resize (0);
00183       //std::cerr << " DISMISSED" << std::endl;
00184       return;
00185       // TODO: this will increase the iteration count, thus reduces robustness if many points are on the top! do it in getSamples ()!
00186     }
00187     //std::cerr << " ACCEPTED" << std::endl;
00188 
00189 
00190     // Distance in normal space - TODO: make setter for eps_angle_ and set these there
00191     double radius = 2 * sin (threshold/2);
00192     //double sqr_radius = radius*radius;
00193 
00194     // TODO: radius search should return number of points found
00195 
00196     // List of points matching the model directly (parallel normal to the sample)
00197     kdtree_->radiusSearch (model_coefficients[3], radius, front_indices_, points_sqr_distances_, input_->points.size ());
00198 
00199     // TODO: pre-check?
00200 
00201     // List of points matching the model's back side (opposing normal to the sample)
00202     NormalT tmp;
00203     tmp.normal[0] = -input_->points[model_coefficients[3]].normal[0];
00204     tmp.normal[1] = -input_->points[model_coefficients[3]].normal[1];
00205     tmp.normal[2] = -input_->points[model_coefficients[3]].normal[2];
00206     kdtree_->radiusSearch (tmp, radius, back_indices_, points_sqr_distances_, input_->points.size ());
00207 
00208     // Number of points matching the model's left side (perpendicular normal to the sample)
00209     NormalT zXn; // cross product of axis and original normal (==-tmp)
00210     zXn.normal[0] = axis_[1]*(-tmp.normal[2]) - axis_[2]*(-tmp.normal[1]);
00211     zXn.normal[1] = axis_[2]*(-tmp.normal[0]) - axis_[0]*(-tmp.normal[2]);
00212     zXn.normal[2] = axis_[0]*(-tmp.normal[1]) - axis_[1]*(-tmp.normal[0]);
00213     kdtree_->radiusSearch (zXn, radius, left_indices_, points_sqr_distances_, input_->points.size ());
00214 
00215     // Number of points matching the model's right side (perpendicular normal to the sample)
00216     tmp.normal[0] = -zXn.normal[0];
00217     tmp.normal[1] = -zXn.normal[1];
00218     tmp.normal[2] = -zXn.normal[2];
00219     kdtree_->radiusSearch (tmp, radius, right_indices_, points_sqr_distances_, input_->points.size ());
00220 
00221     // Concatenate results
00222     inliers = front_indices_;
00223     inliers.insert (inliers.end (), back_indices_.begin (), back_indices_.end ());
00224     inliers.insert (inliers.end (), left_indices_.begin (), left_indices_.end ());
00225     inliers.insert (inliers.end (), right_indices_.begin (), right_indices_.end ());
00226 
00227     // TODO if inlier threshold is too large, there could be overlaps
00228     //sort (inliers.begin (), inliers.end ());
00229     //inliers.erase (unique (inliers.begin (), inliers.end ()), inliers.end ());
00230 
00232   }
00233 
00235 template <typename PointT> bool
00236 pcl::SACModelOrientation<PointT>::isSampleGood(const std::vector<int> &samples) const
00237 {
00238   return true;
00239 }
00240 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


pcl_ias_sample_consensus
Author(s): Nico Blodow, Dejan Pangercic, Zoltan-Csaba MArton
autogenerated on Thu May 23 2013 08:25:03