extract_shape_features.cpp
Go to the documentation of this file.
00001 #include <sstream>
00002 #include <iostream>
00003 #include <fstream>
00004 #include <tabletop_pushing/shape_features.h>
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_ros/transforms.h>
00010 #include <pcl16/ros/conversions.h>
00011 #include <pcl16/common/pca.h>
00012 #include <tabletop_pushing/VisFeedbackPushTrackingAction.h>
00013 #include <tabletop_pushing/point_cloud_segmentation.h>
00014 #include <cpl_visual_features/helpers.h>
00015 #include <cpl_visual_features/features/kernels.h>
00016 #include <time.h> // for srand(time(NULL))
00017 
00018 // libSVM
00019 #include <libsvm/svm.h>
00020 
00021 using namespace cpl_visual_features;
00022 using namespace tabletop_pushing;
00023 
00024 typedef tabletop_pushing::VisFeedbackPushTrackingFeedback PushTrackerState;
00025 
00026 #define XY_RES 0.001
00027 
00028 ShapeLocations start_loc_history_;
00029 double start_loc_arc_length_percent_;
00030 int start_loc_push_sample_count_;
00031 XYZPointCloud hull_cloud_;
00032 PushTrackerState cur_state_;
00033 double point_cloud_hist_res_ = 0.01;
00034 inline int objLocToIdx(double val, double min_val, double max_val)
00035 {
00036   return round((val-min_val)/XY_RES);
00037 }
00038 
00039 inline double sqrDistXY(pcl16::PointXYZ a, pcl16::PointXYZ b)
00040 {
00041   const double dx = a.x-b.x;
00042   const double dy = a.y-b.y;
00043   return dx*dx+dy*dy;
00044 }
00045 
00046 pcl16::PointXYZ worldPointInObjectFrame(pcl16::PointXYZ world_pt, PushTrackerState& cur_state)
00047 {
00048   // Center on object frame
00049   pcl16::PointXYZ shifted_pt;
00050   shifted_pt.x = world_pt.x - cur_state.x.x;
00051   shifted_pt.y = world_pt.y - cur_state.x.y;
00052   shifted_pt.z = world_pt.z - cur_state.z;
00053   double ct = cos(cur_state.x.theta);
00054   double st = sin(cur_state.x.theta);
00055   // Rotate into correct frame
00056   pcl16::PointXYZ obj_pt;
00057   obj_pt.x =  ct*shifted_pt.x + st*shifted_pt.y;
00058   obj_pt.y = -st*shifted_pt.x + ct*shifted_pt.y;
00059   obj_pt.z = shifted_pt.z; // NOTE: Currently assume 2D motion
00060   return obj_pt;
00061 }
00062 
00063 pcl16::PointXYZ objectPointInWorldFrame(pcl16::PointXYZ obj_pt, PushTrackerState& cur_state)
00064 {
00065   // Rotate out of object frame
00066   pcl16::PointXYZ rotated_pt;
00067   double ct = cos(cur_state.x.theta);
00068   double st = sin(cur_state.x.theta);
00069   rotated_pt.x = ct*obj_pt.x - st*obj_pt.y;
00070   rotated_pt.y = st*obj_pt.x + ct*obj_pt.y;
00071   rotated_pt.z = obj_pt.z;  // NOTE: Currently assume 2D motion
00072   // Shift to world frame
00073   pcl16::PointXYZ world_pt;
00074   world_pt.x = rotated_pt.x + cur_state.x.x;
00075   world_pt.y = rotated_pt.y + cur_state.x.y;
00076   world_pt.z = rotated_pt.z + cur_state.z;
00077   return world_pt;
00078 }
00079 
00080 static inline double dist(pcl16::PointXYZ a, pcl16::PointXYZ b)
00081 {
00082   const double dx = a.x-b.x;
00083   const double dy = a.y-b.y;
00084   const double dz = a.z-b.z;
00085   return std::sqrt(dx*dx+dy*dy+dz*dz);
00086 }
00087 
00088 static inline double sqrDist(pcl16::PointXYZ a, pcl16::PointXYZ b)
00089 {
00090   const double dx = a.x-b.x;
00091   const double dy = a.y-b.y;
00092   const double dz = a.z-b.z;
00093   return dx*dx+dy*dy+dz*dz;
00094 }
00095 
00096 ShapeLocation chooseFixedGoalPushStartLoc(ProtoObject& cur_obj, PushTrackerState& cur_state, bool new_object,
00097                                           int num_start_loc_pushes_per_sample, int num_start_loc_sample_locs)
00098 {
00099   double hull_alpha = 0.01;
00100   XYZPointCloud hull_cloud = tabletop_pushing::getObjectBoundarySamples(cur_obj, hull_alpha);
00101   hull_cloud_ = hull_cloud;
00102   cur_state_ = cur_state;
00103 
00104   int rot_idx = -1;
00105   if (new_object)
00106   {
00107     // Reset boundary traversal data
00108     start_loc_arc_length_percent_ = 0.0;
00109     start_loc_push_sample_count_ = 0;
00110     start_loc_history_.clear();
00111 
00112     // NOTE: Initial start location is the dominant orientation
00113     // ROS_INFO_STREAM("Current state theta is: " << cur_state.x.theta);
00114     double min_angle_dist = FLT_MAX;
00115     for (int i = 0; i < hull_cloud.size(); ++i)
00116     {
00117       double theta_i = atan2(hull_cloud.at(i).y - cur_state.x.y, hull_cloud.at(i).x - cur_state.x.x);
00118       double angle_dist_i = fabs(subPIAngle(theta_i - cur_state.x.theta));
00119       if (angle_dist_i < min_angle_dist)
00120       {
00121         min_angle_dist = angle_dist_i;
00122         rot_idx = i;
00123       }
00124     }
00125   }
00126   else
00127   {
00128     // Increment boundary location if necessary
00129     if (start_loc_history_.size() % num_start_loc_pushes_per_sample == 0)
00130     {
00131       start_loc_arc_length_percent_ += 1.0/num_start_loc_sample_locs;
00132       // ROS_INFO_STREAM("Incrementing arc length percent based on: " << num_start_loc_pushes_per_sample);
00133     }
00134 
00135     // Get initial object boundary location in the current world frame
00136     // ROS_INFO_STREAM("init_obj_point: " << start_loc_history_[0].boundary_loc_);
00137     pcl16::PointXYZ init_loc_point = objectPointInWorldFrame(start_loc_history_[0].boundary_loc_, cur_state);
00138     // ROS_INFO_STREAM("init_loc_point: " << init_loc_point);
00139 
00140     // Find index of closest point on current boundary to the initial pushing location
00141     double min_dist = FLT_MAX;
00142     for (int i = 0; i < hull_cloud.size(); ++i)
00143     {
00144       double dist_i = sqrDist(init_loc_point, hull_cloud.at(i));
00145       if (dist_i < min_dist)
00146       {
00147         min_dist = dist_i;
00148         rot_idx = i;
00149       }
00150     }
00151   }
00152   // Test hull_cloud orientation, reverse iteration if it is negative
00153   double pt0_theta = atan2(hull_cloud[rot_idx].y - cur_state.x.y, hull_cloud[rot_idx].x - cur_state.x.x);
00154   int pt1_idx = (rot_idx+1) % hull_cloud.size();
00155   double pt1_theta = atan2(hull_cloud[pt1_idx].y - cur_state.x.y, hull_cloud[pt1_idx].x - cur_state.x.x);
00156   bool reverse_data = false;
00157   if (subPIAngle(pt1_theta - pt0_theta) < 0)
00158   {
00159     reverse_data = true;
00160     // ROS_INFO_STREAM("Reversing data for boundaries");
00161   }
00162 
00163   // Compute cumulative distance around the boundary at each point
00164   std::vector<double> boundary_dists(hull_cloud.size(), 0.0);
00165   double boundary_length = 0.0;
00166   // ROS_INFO_STREAM("rot_idx is " << rot_idx);
00167   for (int i = 1; i <= hull_cloud.size(); ++i)
00168   {
00169     int idx0 = (rot_idx+i-1) % hull_cloud.size();
00170     int idx1 = (rot_idx+i) % hull_cloud.size();
00171     if (reverse_data)
00172     {
00173       idx0 = (hull_cloud.size()+rot_idx-i+1) % hull_cloud.size();
00174       idx1 = (hull_cloud.size()+rot_idx-i) % hull_cloud.size();
00175     }
00176     // NOTE: This makes boundary_dists[rot_idx] = 0.0, and we have no location at 100% the boundary_length
00177     boundary_dists[idx0] = boundary_length;
00178     double loc_dist = dist(hull_cloud[idx0], hull_cloud[idx1]);
00179     boundary_length += loc_dist;
00180   }
00181 
00182   // Find location at start_loc_arc_length_percent_ around the boundary
00183   double desired_boundary_dist = start_loc_arc_length_percent_*boundary_length;
00184   // ROS_INFO_STREAM("Finding location at dist " << desired_boundary_dist << " ~= " << start_loc_arc_length_percent_*100 << "\% of " << boundary_length);
00185   int boundary_loc_idx;
00186   double min_boundary_dist_diff = FLT_MAX;
00187   for (int i = 0; i < hull_cloud.size(); ++i)
00188   {
00189     double boundary_dist_diff_i = fabs(desired_boundary_dist - boundary_dists[i]);
00190     if (boundary_dist_diff_i < min_boundary_dist_diff)
00191     {
00192       min_boundary_dist_diff = boundary_dist_diff_i;
00193       boundary_loc_idx = i;
00194     }
00195   }
00196 
00197   // Get descriptor at the chosen location
00198   // ShapeLocations locs = tabletop_pushing::extractShapeContextFromSamples(hull_cloud, cur_obj, true);
00199   double gripper_spread = 0.05;
00200   pcl16::PointXYZ boundary_loc = hull_cloud[boundary_loc_idx];
00201   ShapeDescriptor sd = tabletop_pushing::extractLocalAndGlobalShapeFeatures(hull_cloud, cur_obj,
00202                                                                             boundary_loc, boundary_loc_idx,
00203                                                                             gripper_spread, hull_alpha,
00204                                                                             point_cloud_hist_res_);
00205   // Add into pushing history in object frame
00206   ShapeLocation s_obj(worldPointInObjectFrame(boundary_loc, cur_state), sd);
00207   start_loc_history_.push_back(s_obj);
00208   ShapeLocation s_world(boundary_loc, sd);
00209   return s_world;
00210 }
00211 
00212 ShapeLocation chooseFixedGoalPushStartLoc(ProtoObject& cur_obj, PushTrackerState& cur_state,
00213                                           pcl16::PointXYZ start_pt)
00214 
00215 {
00216   double hull_alpha = 0.01;
00217   XYZPointCloud hull_cloud = tabletop_pushing::getObjectBoundarySamples(cur_obj, hull_alpha);
00218   hull_cloud_ = hull_cloud;
00219   cur_state_ = cur_state;
00220   double min_dist = FLT_MAX;
00221   int min_dist_idx = 0;
00222   for (int i = 0; i < hull_cloud.size(); ++i)
00223   {
00224     double pt_dist = dist(hull_cloud[i], start_pt);
00225     if (pt_dist < min_dist)
00226     {
00227       min_dist = pt_dist;
00228       min_dist_idx = i;
00229     }
00230   }
00231   double gripper_spread = 0.05;
00232   pcl16::PointXYZ boundary_loc = hull_cloud[min_dist_idx];
00233   ShapeDescriptor sd = tabletop_pushing::extractLocalAndGlobalShapeFeatures(hull_cloud, cur_obj,
00234                                                                             boundary_loc, min_dist_idx,
00235                                                                             gripper_spread,
00236                                                                             hull_alpha, point_cloud_hist_res_);
00237   ShapeLocation s_obj(worldPointInObjectFrame(boundary_loc, cur_state), sd);
00238   start_loc_history_.push_back(s_obj);
00239 
00240   ShapeLocation s_world(boundary_loc, sd);
00241   return s_world;
00242 }
00243 
00244 ShapeLocation chooseLearnedPushStartLoc(ProtoObject& cur_obj, PushTrackerState& cur_state, std::string param_path,
00245                                         float& chosen_score)
00246 {
00247   // Get features for all of the boundary locations
00248   float hull_alpha = 0.01;
00249   XYZPointCloud hull_cloud = tabletop_pushing::getObjectBoundarySamples(cur_obj, hull_alpha);
00250   float gripper_spread = 0.05;
00251   ShapeDescriptors sds = tabletop_pushing::extractLocalAndGlobalShapeFeatures(hull_cloud, cur_obj,
00252                                                                               gripper_spread, hull_alpha,
00253                                                                               point_cloud_hist_res_);
00254   // Set parameters for prediction
00255   // svm_parameter push_parameters;
00256   // push_parameters.svm_type = EPSILON_SVR;
00257   // push_parameters.kernel_type = PRECOMPUTED;
00258   // push_parameters.C = 2.0; // NOTE: only needed for training
00259   // push_parameters.p = 0.3; // NOTE: only needed for training
00260   // push_model.param = push_parameters;
00261 
00262   // TODO: Read in model SVs and coefficients
00263   ROS_INFO_STREAM("reading svm model: " << param_path);
00264   svm_model* push_model;
00265   push_model = svm_load_model(param_path.c_str());
00266   ROS_INFO_STREAM("read svm model: " << param_path);
00267   ROS_INFO_STREAM("svm_parameters.svm_type: " << push_model->param.svm_type);
00268   ROS_INFO_STREAM("svm_parameters.kernel_type: " << push_model->param.kernel_type);
00269   ROS_INFO_STREAM("number SVs: " << push_model->l);
00270 
00271   std::vector<double> pred_push_scores;
00272   chosen_score = FLT_MAX;
00273   int best_idx = -1;
00274   // Perform prediction at all sample locations
00275   for (int i = 0; i < sds.size(); ++i)
00276   {
00277     // ROS_INFO_STREAM("Predicting score for location " << i);
00278     // Set the data vector in libsvm format
00279     svm_node* x = new svm_node[sds[i].size()];
00280     for (int j = 0; j < sds[i].size(); ++j)
00281     {
00282       x[j].index = (j+1); // NOTE: 1 based indices
00283       x[j].value = sds[i][j];
00284     }
00285     // ROS_INFO_STREAM("Created svm_node vector of size: " << sds[i].size());
00286     // Perform prediction and convert out of log spacex
00287     double pred_log_score = svm_predict(push_model, x);
00288     double pred_score = exp(pred_log_score);
00289     // ROS_INFO_STREAM("Predicted score for location " << i << " of " << pred_score << " from log score " << pred_log_score);
00290     // Track the best score to know the location to return
00291     if (pred_score < chosen_score)
00292     {
00293       chosen_score = pred_score;
00294       best_idx = i;
00295     }
00296     pred_push_scores.push_back(pred_score);
00297     delete x;
00298   }
00299   ROS_INFO_STREAM("Chose best push location " << best_idx << " with score " << chosen_score);
00300   ROS_INFO_STREAM("Push location 3D: " << hull_cloud[best_idx]);
00301   // Return the location of the best score
00302   ShapeLocation loc;
00303   if (best_idx >= 0)
00304   {
00305     loc.boundary_loc_ = hull_cloud[best_idx];
00306     loc.descriptor_ = sds[best_idx];
00307   }
00308   return loc;
00309 }
00310 
00311 ShapeDescriptor getTrialDescriptor(std::string cloud_path, pcl16::PointXYZ init_loc, double init_theta, bool new_object)
00312 {
00313   int num_start_loc_pushes_per_sample = 3;
00314   int num_start_loc_sample_locs = 16;
00315 
00316   // pcl16::PointCloud<pcl16::PointXYZ>::Ptr cloud(new pcl16::PointCloud<pcl16::PointXYZ>);
00317   ProtoObject cur_obj;
00318   //.cloud = ; // TODO: COPY from read in one?
00319   PushTrackerState cur_state;
00320   cur_state.x.x = init_loc.x;
00321   cur_state.x.y = init_loc.y;
00322   cur_state.x.theta = init_theta;
00323   cur_state.z = init_loc.z;
00324   cur_obj.centroid[0] = cur_state.x.x;
00325   cur_obj.centroid[1] = cur_state.x.y;
00326   cur_obj.centroid[2] = cur_state.z;
00327   ROS_INFO_STREAM("Getting cloud: " << cloud_path);
00328   if (pcl16::io::loadPCDFile<pcl16::PointXYZ> (cloud_path, cur_obj.cloud) == -1) //* load the file
00329   {
00330     ROS_ERROR_STREAM("Couldn't read file " << cloud_path);
00331   }
00332   ROS_INFO_STREAM("Got cloud: " << cloud_path);
00333   ShapeLocation sl = chooseFixedGoalPushStartLoc(cur_obj, cur_state, new_object, num_start_loc_pushes_per_sample,
00334                                                  num_start_loc_sample_locs);
00335   return sl.descriptor_;
00336 }
00337 
00338 ShapeDescriptor getTrialDescriptor(std::string cloud_path, pcl16::PointXYZ init_loc, double init_theta,
00339                                    pcl16::PointXYZ start_pt)
00340 {
00341   int num_start_loc_pushes_per_sample = 3;
00342   int num_start_loc_sample_locs = 16;
00343 
00344   // pcl16::PointCloud<pcl16::PointXYZ>::Ptr cloud(new pcl16::PointCloud<pcl16::PointXYZ>);
00345   ProtoObject cur_obj;
00346   //.cloud = ; // TODO: COPY from read in one?
00347   PushTrackerState cur_state;
00348   cur_state.x.x = init_loc.x;
00349   cur_state.x.y = init_loc.y;
00350   cur_state.x.theta = init_theta;
00351   cur_state.z = init_loc.z;
00352   cur_obj.centroid[0] = cur_state.x.x;
00353   cur_obj.centroid[1] = cur_state.x.y;
00354   cur_obj.centroid[2] = cur_state.z;
00355   ROS_INFO_STREAM("Getting cloud: " << cloud_path);
00356   if (pcl16::io::loadPCDFile<pcl16::PointXYZ> (cloud_path, cur_obj.cloud) == -1) //* load the file
00357   {
00358     ROS_ERROR_STREAM("Couldn't read file " << cloud_path);
00359   }
00360   ROS_INFO_STREAM("Got cloud: " << cloud_path);
00361   ShapeLocation sl = chooseFixedGoalPushStartLoc(cur_obj, cur_state, start_pt);
00362   return sl.descriptor_;
00363 }
00364 
00365 ShapeLocation predictPushLocation(std::string cloud_path, pcl16::PointXYZ init_loc, double init_theta,
00366                                   pcl16::PointXYZ start_pt, std::string param_path)
00367 {
00368   int num_start_loc_pushes_per_sample = 3;
00369   int num_start_loc_sample_locs = 16;
00370 
00371   // pcl16::PointCloud<pcl16::PointXYZ>::Ptr cloud(new pcl16::PointCloud<pcl16::PointXYZ>);
00372   ProtoObject cur_obj;
00373   //.cloud = ; // TODO: COPY from read in one?
00374   PushTrackerState cur_state;
00375   cur_state.x.x = init_loc.x;
00376   cur_state.x.y = init_loc.y;
00377   cur_state.x.theta = init_theta;
00378   cur_state.z = init_loc.z;
00379   cur_obj.centroid[0] = cur_state.x.x;
00380   cur_obj.centroid[1] = cur_state.x.y;
00381   cur_obj.centroid[2] = cur_state.z;
00382   ROS_INFO_STREAM("Getting cloud: " << cloud_path);
00383   if (pcl16::io::loadPCDFile<pcl16::PointXYZ> (cloud_path, cur_obj.cloud) == -1) //* load the file
00384   {
00385     ROS_ERROR_STREAM("Couldn't read file " << cloud_path);
00386   }
00387   ROS_INFO_STREAM("Got cloud: " << cloud_path);
00388   float chosen_score;
00389   ShapeLocation sl = chooseLearnedPushStartLoc(cur_obj, cur_state, param_path, chosen_score);
00390   return sl;
00391 }
00392 
00393 class TrialStuff
00394 {
00395  public:
00396   TrialStuff(double init_x_, double init_y_, double init_z_, double init_theta_, std::string trial_id_, bool new_object_,
00397              double push_x_, double push_y_, double push_z_) :
00398       init_loc(init_x_, init_y_, init_z_), init_theta(init_theta_), trial_id(trial_id_), new_object(new_object_),
00399       start_pt(push_x_, push_y_, push_z_)
00400   {
00401   }
00402   pcl16::PointXYZ init_loc;
00403   double init_theta;
00404   std::string trial_id;
00405   bool new_object;
00406   pcl16::PointXYZ start_pt;
00407 };
00408 
00409 std::vector<TrialStuff> getTrialsFromFile(std::string aff_file_name)
00410 {
00411   std::vector<TrialStuff> trials;
00412   std::ifstream trials_in(aff_file_name.c_str());
00413 
00414   bool next_line_trial = false;
00415   bool trial_is_start = true;
00416   int line_count = 0;
00417   int object_comment = 0;
00418   int trial_starts = 0;
00419   int bad_stops = 0;
00420   int good_stops = 0;
00421   int control_headers = 0;
00422   bool new_object = true;
00423   while(trials_in.good())
00424   {
00425     char c_line[4096];
00426     trials_in.getline(c_line, 4096);
00427     line_count++;
00428     if (next_line_trial)
00429     {
00430       // ROS_INFO_STREAM("Parsing trial_line: ");
00431       next_line_trial = false;
00432 
00433       // TODO: Parse this line!
00434       std::stringstream trial_line;
00435       trial_line << c_line;
00436       char trial_id_c[4096];
00437       trial_line.getline(trial_id_c, 4096, ' ');
00438       std::stringstream trial_id;
00439       trial_id << trial_id_c;
00440       // ROS_INFO_STREAM("Read trial_id: " << trial_id.str());
00441       double init_x, init_y, init_z, init_theta;
00442       trial_line >> init_x >> init_y >> init_z >> init_theta;
00443       double final_x, final_y, final_z, final_theta;
00444       trial_line >> final_x >> final_y >> final_z >> final_theta;
00445       double goal_x, goal_y, goal_theta;
00446       trial_line >> goal_x >> goal_y >> goal_theta;
00447       double push_start_x, push_start_y, push_start_z, push_start_theta;
00448       trial_line >> push_start_x >> push_start_y >> push_start_z;
00449 
00450       // ROS_INFO_STREAM("Init pose (" << init_x << ", " << init_y << ", " << init_z << ", " << init_theta << ")");
00451       // TODO: Read in start_point?!?
00452       new_object = !trials.size();
00453       TrialStuff trial(init_x, init_y, init_z, init_theta, trial_id.str(), new_object,
00454                        push_start_x, push_start_y, push_start_z);
00455       trials.push_back(trial);
00456     }
00457     if (c_line[0] == '#')
00458     {
00459       if (c_line[2] == 'o')
00460       {
00461         object_comment++;
00462         if (trial_is_start)
00463         {
00464           next_line_trial = true;
00465           trial_starts += 1;
00466           // ROS_INFO_STREAM("Read in start line");
00467         }
00468         else
00469         {
00470           // ROS_INFO_STREAM("Read in end line");
00471           good_stops++;
00472         }
00473         // Switch state
00474         trial_is_start = !trial_is_start;
00475       }
00476       else if (c_line[2] == 'x')
00477       {
00478         control_headers += 1;
00479       }
00480       else if (c_line[1] == 'B')
00481       {
00482         // ROS_WARN_STREAM("Read in bad line" << c_line);
00483         trial_is_start = true;
00484         trials.pop_back();
00485         bad_stops += 1;
00486       }
00487     }
00488   }
00489   trials_in.close();
00490 
00491   ROS_INFO_STREAM("Read in: " << line_count << " lines");
00492   ROS_INFO_STREAM("Read in: " << control_headers << " control headers");
00493   ROS_INFO_STREAM("Read in: " << object_comment << " trial headers");
00494   ROS_INFO_STREAM("Classified: " << trial_starts << " as starts");
00495   ROS_INFO_STREAM("Classified: " << bad_stops << " as bad");
00496   ROS_INFO_STREAM("Classified: " << good_stops << " as good");
00497   ROS_INFO_STREAM("Read in: " << trials.size() << " trials");
00498   return trials;
00499 }
00500 
00501 void writeNewFile(std::string out_file_name, std::vector<TrialStuff> trials, ShapeDescriptors descriptors)
00502 {
00503   std::ofstream out_file(out_file_name.c_str());
00504   for (unsigned int i = 0; i < descriptors.size(); ++i)
00505   {
00506     for (unsigned int j = 0; j < descriptors[i].size(); ++j)
00507     {
00508       out_file << descriptors[i][j] << " ";
00509     }
00510     out_file << "\n";
00511   }
00512   out_file.close();
00513 }
00514 
00515 void writeNewExampleFile(std::string out_file_name, std::vector<TrialStuff> trials, ShapeDescriptors descriptors,
00516                          std::vector<double>& push_scores)
00517 {
00518   ROS_INFO_STREAM("Writing example file: " << out_file_name);
00519   std::ofstream out_file(out_file_name.c_str());
00520   for (unsigned int i = 0; i < descriptors.size(); ++i)
00521   {
00522     out_file << push_scores[i] << " ";
00523     for (unsigned int j = 0; j < descriptors[i].size(); ++j)
00524     {
00525       if (descriptors[i][j] != 0.0)
00526       {
00527         out_file << (j+1) << ":" << descriptors[i][j] << " ";
00528       }
00529     }
00530     out_file << "\n";
00531   }
00532   out_file.close();
00533 }
00534 
00535 std::vector<double> readScoreFile(std::string file_path)
00536 {
00537   std::ifstream data_in(file_path.c_str());
00538   std::vector<double> scores;
00539   while (data_in.good())
00540   {
00541     char c_line[4096];
00542     data_in.getline(c_line, 4096);
00543     std::stringstream line;
00544     line << c_line;
00545     double y;
00546     line >> y;
00547     if (!data_in.eof())
00548     {
00549       scores.push_back(y);
00550     }
00551   }
00552   data_in.close();
00553   return scores;
00554 }
00555 
00556 void drawScores(std::vector<double>& push_scores, std::string out_file_path)
00557 {
00558   double max_y = 0.3;
00559   double min_y = -0.3;
00560   double max_x = 0.3;
00561   double min_x = -0.3;
00562   int rows = ceil((max_y-min_y)/XY_RES);
00563   int cols = ceil((max_x-min_x)/XY_RES);
00564   cv::Mat footprint(rows, cols, CV_8UC3, cv::Scalar(255,255,255));
00565 
00566   for (int i = 0; i < hull_cloud_.size(); ++i)
00567   {
00568     pcl16::PointXYZ obj_pt =  worldPointInObjectFrame(hull_cloud_[i], cur_state_);
00569     int img_x = objLocToIdx(obj_pt.x, min_x, max_x);
00570     int img_y = objLocToIdx(obj_pt.y, min_y, max_y);
00571     cv::Scalar color(128, 0, 0);
00572     cv::circle(footprint, cv::Point(img_x, img_y), 1, color, 3);
00573   }
00574   // HACK: Normalize across object classes
00575   double max_score = 0.0602445;
00576   for (int i = 0; i < start_loc_history_.size(); ++i)
00577   {
00578     int x = objLocToIdx(start_loc_history_[i].boundary_loc_.x, min_x, max_x);
00579     int y = objLocToIdx(start_loc_history_[i].boundary_loc_.y, min_y, max_y);
00580     // double score = -log(push_scores[i])/10;
00581     double score = push_scores[i]/M_PI;
00582     ROS_INFO_STREAM("Score " << score);
00583     cv::Scalar color(0, score*255, (1-score)*255);
00584     // color[0] = 0.5;
00585     // color[1] = score;
00586     // color[2] = 0.5;
00587     // footprint.at<cv::Vec3f>(r,c) = color;
00588     cv::circle(footprint, cv::Point(x,y), 1, color, 3);
00589     cv::circle(footprint, cv::Point(x,y), 2, color, 3);
00590     cv::circle(footprint, cv::Point(x,y), 3, color, 3);
00591   }
00592   // ROS_INFO_STREAM("Max score is: " << max_score);
00593   ROS_INFO_STREAM("Writing image: " << out_file_path);
00594   cv::imwrite(out_file_path, footprint);
00595 
00596   cv::imshow("Push score", footprint);
00597   cv::waitKey();
00598 }
00599 
00600 pcl16::PointXYZ pointClosestToAngle(double major_angle, XYZPointCloud& hull_cloud, Eigen::Vector4f centroid)
00601 {
00602   pcl16::PointXYZ closest;
00603   double min_angle_dist = FLT_MAX;
00604   for (int i = 0; i < hull_cloud.size(); ++i)
00605   {
00606     double angle_dist = fabs(major_angle - atan2(hull_cloud[i].y - centroid[1], hull_cloud[i].x - centroid[0]));
00607     if (angle_dist < min_angle_dist)
00608     {
00609       closest = hull_cloud[i];
00610       min_angle_dist = angle_dist;
00611     }
00612   }
00613   ROS_INFO_STREAM("Closest point " << closest << " at angle dist " << min_angle_dist);
00614   return closest;
00615 }
00616 
00617 void getMajorMinorBoundaryDists(std::string cloud_path, pcl16::PointXYZ init_loc, pcl16::PointXYZ start_pt,
00618                                 double& major_dist, double& minor_dist)
00619 {
00620   ProtoObject cur_obj;
00621   cur_obj.centroid[0] = init_loc.x;
00622   cur_obj.centroid[1] = init_loc.y;
00623   cur_obj.centroid[2] = init_loc.z;
00624   ROS_INFO_STREAM("Getting cloud: " << cloud_path);
00625   if (pcl16::io::loadPCDFile<pcl16::PointXYZ> (cloud_path, cur_obj.cloud) == -1) //* load the file
00626   {
00627     ROS_ERROR_STREAM("Couldn't read file " << cloud_path);
00628   }
00629   ROS_INFO_STREAM("Got cloud: " << cloud_path);
00630 
00631   float hull_alpha = 0.01;
00632   XYZPointCloud hull_cloud = tabletop_pushing::getObjectBoundarySamples(cur_obj, hull_alpha);
00633   hull_cloud_ = hull_cloud;
00634   double min_dist = FLT_MAX;
00635   int min_dist_idx = 0;
00636   for (int i = 0; i < hull_cloud.size(); ++i)
00637   {
00638     double pt_dist = dist(hull_cloud[i], start_pt);
00639     if (pt_dist < min_dist)
00640     {
00641       min_dist = pt_dist;
00642       min_dist_idx = i;
00643     }
00644   }
00645   float gripper_spread = 0.05;
00646   pcl16::PointXYZ boundary_loc = hull_cloud[min_dist_idx];
00647 
00648   // TODO: Get major/minor axis of hull_cloud
00649   pcl16::PCA<pcl16::PointXYZ> pca;
00650   pca.setInputCloud(hull_cloud.makeShared());
00651   Eigen::Vector3f eigen_values = pca.getEigenValues();
00652   Eigen::Matrix3f eigen_vectors = pca.getEigenVectors();
00653   Eigen::Vector4f centroid = pca.getMean();
00654   double minor_angle = atan2(eigen_vectors(1,0), eigen_vectors(0,0));
00655   double major_angle = minor_angle-0.5*M_PI;
00656 
00657   // TODO: Figure out points a and b of major axis intersection
00658   pcl16::PointXYZ a = pointClosestToAngle(major_angle, hull_cloud, centroid);
00659   pcl16::PointXYZ b = pointClosestToAngle(subPIAngle(major_angle+M_PI), hull_cloud, centroid);
00660   major_dist = std::min(sqrDistXY(boundary_loc, a), sqrDistXY(boundary_loc, b));
00661   // TODO: Figure out points c and d of minor axis intersection
00662   pcl16::PointXYZ c  = pointClosestToAngle(minor_angle, hull_cloud, centroid);
00663   pcl16::PointXYZ d = pointClosestToAngle(subPIAngle(minor_angle+M_PI), hull_cloud, centroid);
00664   minor_dist = std::min(sqrDistXY(boundary_loc, c), sqrDistXY(boundary_loc, d));
00665 }
00666 
00667 int main(int argc, char** argv)
00668 {
00669   int seed = time(NULL);
00670   srand(seed);
00671 
00672   std::string aff_file_path(argv[1]);
00673   std::string data_directory_path(argv[2]);
00674   std::string out_file_path(argv[3]);
00675   std::vector<TrialStuff> trials = getTrialsFromFile(aff_file_path);
00676   std::string score_file = "";
00677   bool draw_scores = argc > 4;
00678   ROS_INFO_STREAM("trials.size(): " << trials.size());
00679   std::vector<double> push_scores;
00680   if (draw_scores)
00681   {
00682     score_file = argv[4];
00683     push_scores = readScoreFile(score_file);
00684     ROS_INFO_STREAM("scores.size(): " << push_scores.size());
00685   }
00686 
00687   bool test_straw_man = false;
00688   std::ofstream straw_scores_stream("/home/thermans/Desktop/straw_scores.txt");
00689   double max_score = -100.0;
00690   ShapeDescriptors descriptors;
00691   for (unsigned int i = 0; i < trials.size(); ++i)
00692   {
00693     std::string trial_id = trials[i].trial_id;
00694     pcl16::PointXYZ init_loc = trials[i].init_loc;
00695     double init_theta = trials[i].init_theta;
00696     bool new_object = trials[i].new_object;
00697     ROS_INFO_STREAM("trial_id: " << trial_id);
00698     ROS_INFO_STREAM("init_loc: " << init_loc);
00699     ROS_INFO_STREAM("init_theta: " << init_theta);
00700     ROS_INFO_STREAM("new object: " << new_object);
00701     ROS_INFO_STREAM("start_pt: " << trials[i].start_pt);
00702     std::stringstream cloud_path;
00703     cloud_path << data_directory_path << trial_id << "_obj_cloud.pcd";
00704 
00705     ShapeDescriptor sd = getTrialDescriptor(cloud_path.str(), init_loc, init_theta, trials[i].start_pt);
00706     // std::string param_path = "/home/thermans/Dropbox/Data/start_loc_learning/point_push/examples_line_dist/push_svm_1.model";
00707     // ShapeLocation chosen = predictPushLocation(cloud_path.str(), init_loc, init_theta, trials[i].start_pt, param_path);
00708 
00709     // if (draw_scores)
00710     // {
00711     //   // TODO: Get the image, draw the shape context, highlight score color
00712     //   // TODO: Get projection matrix
00713     //   std::stringstream hull_img_path;
00714     //   hull_img_path << data_directory_path << trial_id << "_obj_hull_disp.png";
00715     //   cv::Mat disp_img;
00716     //   ROS_INFO_STREAM("Reading image: " << hull_img_path.str());
00717     //   disp_img = cv::imread(hull_img_path.str());
00718     //   ROS_INFO_STREAM("Read image: " << hull_img_path.str());
00719     //   // double score = -log(push_scores[i])/10;
00720     //   double score = push_scores[i]/M_PI;
00721     //   cv::Vec3b score_color(0, score*255, (1-score)*255);
00722     //   for (int r = 0; r < disp_img.rows; ++r)
00723     //   {
00724     //     for (int c = 0; c < disp_img.cols; ++c)
00725     //     {
00726     //       if (disp_img.at<cv::Vec3b>(r,c)[0] == 0 && disp_img.at<cv::Vec3b>(r,c)[1] == 0 &&
00727     //           disp_img.at<cv::Vec3b>(r,c)[2] == 255)
00728     //       {
00729     //         disp_img.at<cv::Vec3b>(r,c) = score_color;
00730     //       }
00731     //       else if (disp_img.at<cv::Vec3b>(r,c)[0] == 0 && disp_img.at<cv::Vec3b>(r,c)[1] == 255 &&
00732     //                disp_img.at<cv::Vec3b>(r,c)[2] == 0)
00733     //       {
00734     //         disp_img.at<cv::Vec3b>(r,c) = cv::Vec3b(255,0,0);
00735     //       }
00736 
00737     //     }
00738     //   }
00739     //   ROS_INFO_STREAM("Score is " << push_scores[i] << "\n");
00740     //   cv::imshow("hull", disp_img);
00741     //   // cv::waitKey();
00742     //   if (push_scores[i] > max_score)
00743     //   {
00744     //     max_score = push_scores[i];
00745     //   }
00746     // }
00747     descriptors.push_back(sd);
00748   }
00749   // Feature testing below
00750   // ROS_INFO_STREAM("Constructing features matrices for x^2 kernel");
00751   // int local_hist_width = 6;
00752   // int local_hist_size = local_hist_width*local_hist_width;
00753   // int global_hist_size = 60;
00754   // cv::Mat local_feats(cv::Size(local_hist_size, descriptors.size()), CV_64FC1, cv::Scalar(0.0));
00755   // cv::Mat global_feats(cv::Size(global_hist_size, descriptors.size()), CV_64FC1, cv::Scalar(0.0));
00756   // std::vector<std::vector<double> > local_feats;
00757   // std::vector<std::vector<double> > global_feats;
00758   // cv::Mat global_feats(cv::Size(global_hist_size, descriptors.size()), CV_64FC1, cv::Scalar(0.0));
00759   // ROS_INFO_STREAM("feat_length: " << descriptors[0].size());
00760   // for (int r = 0; r < descriptors.size(); ++r)
00761   // {
00762   //   std::vector<double> local_row;
00763   //   local_feats.push_back(local_row);
00764   //   std::vector<double> global_row;
00765   //   global_feats.push_back(global_row);
00766   //   for (int c = 0; c < local_hist_size; ++c)
00767   //   {
00768   //     local_feats[r].push_back(descriptors[r][c]);
00769   //   }
00770   //   for (int c = local_hist_size; c < local_hist_size+global_hist_size; ++c)
00771   //   {
00772   //     global_feats[r].push_back(descriptors[r][c]);
00773   //   }
00774   // }
00775   // ROS_INFO_STREAM("Computing x^2 for " << descriptors.size() << " descriptors");
00776   // ROS_INFO_STREAM("Global_feats.size() (" << global_feats.size() << ", " << global_feats[0].size() << ")");
00777   // ROS_INFO_STREAM("Local_feats.size() (" << local_feats.size() << ", " << local_feats[0].size() << ")");
00778   // std::vector<std::vector<double> > K_global = chiSquareKernelBatch(global_feats, global_feats, 2.0);
00779   // std::vector<std::vector<double> > K_local = chiSquareKernelBatch(local_feats, local_feats, 2.5);
00780   // std::stringstream global_out;
00781   // for (int r = 0; r < K_global.size(); ++r)
00782   // {
00783   //   for (int c = 0; c < K_global[r].size(); ++c)
00784   //   {
00785   //     global_out << " " << K_global[r][c];
00786   //   }
00787   //   global_out << "\n";
00788   // }
00789   // ROS_INFO_STREAM("Global: \n" << global_out.str());
00790   // std::stringstream local_out;
00791   // for (int r = 0; r < K_local.size(); ++r)
00792   // {
00793   //   for (int c = 0; c < K_local[r].size(); ++c)
00794   //   {
00795   //     local_out << " " << K_local[r][c];
00796   //   }
00797   //   local_out << "\n";
00798   // }
00799   // ROS_INFO_STREAM("Local: \n" << local_out.str());
00800   // std::stringstream line_out;
00801   // for (int c = 0; c < local_feats[0].size(); ++c)
00802   // {
00803   //   for (int r = 0; r < local_feats.size(); ++r)
00804   //   {
00805   //     if (local_feats[r][c] > 0)
00806   //     {
00807   //       line_out << "\t(" << (r+1) << ", " << (c+1) << ")\t" << local_feats[r][c] << "\n";
00808   //     }
00809   //   }
00810   // }
00811   // ROS_INFO_STREAM("feat: " << line_out.str());
00812 
00813     // if (test_straw_man)
00814     // {
00815     //   double major_dist_i = 0.0;
00816     //   double minor_dist_i = 0.0;
00817     //   getMajorMinorBoundaryDists(cloud_path.str(), init_loc, trials[i].start_pt, major_dist_i, minor_dist_i);
00818     //   straw_scores_stream << push_scores[i] << " " << major_dist_i << " " << minor_dist_i << "\n";
00819     // }
00820 
00821   // std::stringstream out_file;
00822   // writeNewExampleFile(out_file_path, trials, descriptors, push_scores);
00823   if (draw_scores)
00824   {
00825     // TODO: Pass in info to write these to disk again?
00826     drawScores(push_scores, out_file_path);
00827     // drawScores(push_scores);
00828   }
00829   return 0;
00830 }


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