compare_object_boundaries.cpp
Go to the documentation of this file.
00001 #include <string>
00002 #include <sstream>
00003 #include <iostream>
00004 #include <fstream>
00005 #include <ros/ros.h>
00006 #include <pcl16/point_cloud.h>
00007 #include <pcl16/point_types.h>
00008 #include <pcl16/io/pcd_io.h>
00009 #include <pcl16/surface/concave_hull.h>
00010 #include <tabletop_pushing/shape_features.h>
00011 #include <tabletop_pushing/point_cloud_segmentation.h>
00012 #include <tabletop_pushing/VisFeedbackPushTrackingAction.h>
00013 // PCL
00014 #include <pcl16/common/pca.h>
00015 
00016 // cpl_visual_features
00017 #include <cpl_visual_features/helpers.h>
00018 
00019 typedef tabletop_pushing::VisFeedbackPushTrackingFeedback PushTrackerState;
00020 using cpl_visual_features::subPIAngle;
00021 using namespace tabletop_pushing;
00022 
00023 
00024 double getThetaFromEllipse(cv::RotatedRect& obj_ellipse)
00025 {
00026   return subPIAngle(DEG2RAD(obj_ellipse.angle)+0.5*M_PI);
00027 }
00028 
00029 void fitHullEllipse(XYZPointCloud& hull_cloud, cv::RotatedRect& obj_ellipse)
00030 {
00031   Eigen::Vector3f eigen_values;
00032   Eigen::Matrix3f eigen_vectors;
00033   Eigen::Vector4f centroid;
00034 
00035   // HACK: Copied/adapted from PCA in PCL because PCL was seg faulting after an update on the robot
00036   // Compute mean
00037   centroid = Eigen::Vector4f::Zero();
00038   // ROS_INFO_STREAM("Getting centroid");
00039   pcl16::compute3DCentroid(hull_cloud, centroid);
00040   // Compute demeanished cloud
00041   Eigen::MatrixXf cloud_demean;
00042   // ROS_INFO_STREAM("Demenaing point cloud");
00043   pcl16::demeanPointCloud(hull_cloud, centroid, cloud_demean);
00044 
00045   // Compute the product cloud_demean * cloud_demean^T
00046   // ROS_INFO_STREAM("Getting alpha");
00047   Eigen::Matrix3f alpha = static_cast<Eigen::Matrix3f> (cloud_demean.topRows<3> () * cloud_demean.topRows<3> ().transpose ());
00048 
00049   // Compute eigen vectors and values
00050   // ROS_INFO_STREAM("Getting eigenvectors");
00051   Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> evd (alpha);
00052   // Organize eigenvectors and eigenvalues in ascendent order
00053   for (int i = 0; i < 3; ++i)
00054   {
00055     eigen_values[i] = evd.eigenvalues()[2-i];
00056     eigen_vectors.col(i) = evd.eigenvectors().col(2-i);
00057   }
00058 
00059   // try{
00060   //   pca.setInputCloud(cloud_no_z.makeShared());
00061   //   ROS_INFO_STREAM("Getting mean");
00062   //   centroid = pca.getMean();p
00063   //   ROS_INFO_STREAM("Getting eiven values");
00064   //   eigen_values = pca.getEigenValues();
00065   //   ROS_INFO_STREAM("Getting eiven vectors");
00066   //   eigen_vectors = pca.getEigenVectors();
00067   // } catch(pcl16::InitFailedException ife)
00068   // {
00069   //   ROS_WARN_STREAM("Failed to compute PCA");
00070   //   ROS_WARN_STREAM("ife: " << ife.what());
00071   // }
00072 
00073   obj_ellipse.center.x = centroid[0];
00074   obj_ellipse.center.y = centroid[1];
00075   obj_ellipse.angle = RAD2DEG(atan2(eigen_vectors(1,0), eigen_vectors(0,0))-0.5*M_PI);
00076   // NOTE: major axis is defined by height
00077   obj_ellipse.size.height = std::max(eigen_values(0)*0.1, 0.07);
00078   obj_ellipse.size.width = std::max(eigen_values(1)*0.1, 0.03);
00079 
00080 }
00081 
00082 XYZPointCloud getHullFromPCDFile(std::string cloud_path)
00083 {
00084   XYZPointCloud cloud;
00085   if (pcl16::io::loadPCDFile<pcl16::PointXYZ>(cloud_path, cloud) == -1) //* load the file
00086   {
00087     ROS_ERROR_STREAM("Couldn't read file " << cloud_path);
00088   }
00089   // ROS_INFO_STREAM("Cloud has " << cloud.size() << " points.");
00090   XYZPointCloud hull_cloud;
00091   float hull_alpha = 0.01;
00092   pcl16::ConcaveHull<pcl16::PointXYZ> hull;
00093   hull.setDimension(2);  // NOTE: Get 2D projection of object
00094   hull.setInputCloud(cloud.makeShared());
00095   hull.setAlpha(hull_alpha);
00096   hull.reconstruct(hull_cloud);
00097   // ROS_INFO_STREAM("Hull has " << hull_cloud.size() << " points.");
00098   return hull_cloud;
00099 }
00100 
00101 float compareObjectHullShapes(XYZPointCloud& hull_cloud_a,XYZPointCloud& hull_cloud_b)
00102 {
00103   // Extract shape features from hull_a & hull_b and perform alignment
00104   double match_cost;
00105   cpl_visual_features::Path matches = compareBoundaryShapes(hull_cloud_a, hull_cloud_b, match_cost);
00106   // Visualize the matches & report the score
00107   // ROS_INFO_STREAM("Found minimum cost match of: " << match_cost);
00108   PushTrackerState state;
00109   cv::RotatedRect obj_ellipse;
00110   fitHullEllipse(hull_cloud_a, obj_ellipse);
00111   state.x.theta = getThetaFromEllipse(obj_ellipse);
00112   // Get (x,y) centroid of boundary
00113   state.x.x = obj_ellipse.center.x;
00114   state.x.y = obj_ellipse.center.y;
00115   cv::Mat match_img = visualizeObjectBoundaryMatches(hull_cloud_a, hull_cloud_b, state, matches);
00116   cv::imshow("Object boundary matches", match_img);
00117   cv::waitKey(3);
00118   return match_cost;
00119 }
00120 
00121 int main(int argc, char** argv)
00122 {
00123   // Parse file names for a and b
00124   if (argc != 5)
00125   {
00126     ROS_INFO_STREAM("usage: " << argv[0] << " cloud_a_path cloud_b_path");
00127     return -1;
00128   }
00129   // TODO: Cycle through multiple directories comparing values and computing statistics
00130   std::string cloud_a_base_path(argv[1]);
00131   std::string cloud_b_base_path(argv[2]);
00132   int num_a = atoi(argv[3]);
00133   int num_b = atoi(argv[4]);
00134   std::vector<std::vector<float> > match_scores;
00135   float score_sum = 0;
00136   for (int a = 0; a < num_a; ++a)
00137   {
00138     std::stringstream cloud_a_path;
00139     cloud_a_path << cloud_a_base_path << a << ".pcd";
00140     // Read in point clouds for a & b and extract the hulls
00141     XYZPointCloud hull_cloud_a = getHullFromPCDFile(cloud_a_path.str());
00142     std::vector<float> scores_b;
00143     float score_sum_b = 0;
00144     for (int b = 0; b < num_b; ++b)
00145     {
00146       std::stringstream cloud_b_path;
00147       cloud_b_path << cloud_b_base_path << b << ".pcd";
00148       XYZPointCloud hull_cloud_b = getHullFromPCDFile(cloud_b_path.str());
00149       float match_score = compareObjectHullShapes(hull_cloud_a, hull_cloud_b);
00150       scores_b.push_back(match_score);
00151       score_sum += match_score;
00152       score_sum_b += match_score;
00153     }
00154     match_scores.push_back(scores_b);
00155     ROS_INFO_STREAM("Mean score: " << score_sum_b/num_b);
00156   }
00157   ROS_INFO_STREAM("Overall mean score: " << score_sum/(num_b*num_a));
00158   // TODO: Examine interclass and intraclass distributions of score matches
00159   return 0;
00160 }


tabletop_pushing
Author(s): Tucker Hermans
autogenerated on Wed Nov 27 2013 11:59:44