Go to the documentation of this file.00001
00013
00014 #include "rail_recognition/PointCloudMetrics.h"
00015 #include "rail_recognition/PointCloudRecognizer.h"
00016
00017
00018 #include <pcl/kdtree/kdtree_flann.h>
00019 #include <pcl/registration/icp.h>
00020
00021 using namespace std;
00022 using namespace rail::pick_and_place;
00023
00024 PointCloudRecognizer::PointCloudRecognizer()
00025 {
00026 }
00027
00028 bool PointCloudRecognizer::recognizeObject(rail_manipulation_msgs::SegmentedObject &object,
00029 const vector<PCLGraspModel> &candidates) const
00030 {
00031
00032 if (candidates.empty())
00033 {
00034 ROS_WARN("Candidate object list is empty. Nothing to compare segmented object to.");
00035 return false;
00036 }
00037 if (object.point_cloud.data.empty())
00038 {
00039 ROS_WARN("Segmented object point cloud is empty. Nothing to compare candidate objects to.");
00040 return false;
00041 }
00042
00043
00044 pcl::PointCloud<pcl::PointXYZRGB>::Ptr object_point_cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
00045 point_cloud_metrics::rosPointCloud2ToPCLPointCloud(object.point_cloud, object_point_cloud);
00046
00047
00048 double object_r, object_g, object_b, object_std_dev_r, object_std_dev_g, object_std_dev_b;
00049 point_cloud_metrics::calculateAvgColors(object_point_cloud, object_r, object_g, object_b);
00050 point_cloud_metrics::calculateStdDevColors(object_point_cloud, object_std_dev_r, object_std_dev_g,
00051 object_std_dev_b, object_r, object_g, object_b);
00052 point_cloud_metrics::filterPointCloudOutliers(object_point_cloud);
00053 point_cloud_metrics::transformToOrigin(object_point_cloud, object.centroid);
00054
00055
00056 double min_score = numeric_limits<double>::infinity();
00057 size_t min_index;
00058 tf2::Transform min_icp_tf;
00059 for (size_t i = 0; i < candidates.size(); i++)
00060 {
00061 const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &candidate_point_cloud = candidates[i].getPCLPointCloud();
00062
00063
00064 if (!candidate_point_cloud->empty())
00065 {
00066
00067
00068
00069
00070
00071 tf2::Transform cur_icp_tf;
00072 double score = this->scoreRegistration(candidate_point_cloud, object_point_cloud, cur_icp_tf);
00073 if (score < min_score)
00074 {
00075 min_score = score;
00076 min_index = i;
00077 min_icp_tf = cur_icp_tf;
00078 }
00079
00080
00081
00082
00083
00084 }
00085 }
00086
00087
00088 if (min_score > SCORE_CONFIDENCE_THRESHOLD)
00089 {
00090 ROS_INFO("Minimum recognition score did not exceed confidence threshold.");
00091 ROS_INFO("Min score: %lf", min_score);
00092 return false;
00093 }
00094 ROS_INFO("Object successfully recognized as: %s", object.name.c_str());
00095
00096
00097 object.name = candidates[min_index].getObjectName();
00098 object.model_id = candidates[min_index].getID();
00099 object.confidence = min_score;
00100 object.recognized = true;
00101 object.orientation.w = 1.0;
00102 object.grasps.clear();
00103
00104
00105 vector<graspdb::Grasp> possible_grasps;
00106 this->computeGraspList(min_icp_tf, object.centroid, candidates[min_index].getGrasps(), possible_grasps);
00107
00108
00109 vector<double> success_rates;
00110 for (size_t i = 0; i < possible_grasps.size(); i++)
00111 {
00112 double rate = possible_grasps[i].getSuccessRate();
00113 geometry_msgs::PoseStamped pose = possible_grasps[i].getGraspPose().toROSPoseStampedMessage();
00114
00115 pose.header.frame_id = object.point_cloud.header.frame_id;
00116
00117
00118 if (rate > 0 || possible_grasps[i].getAttempts() == 0)
00119 {
00120
00121 bool inserted = false;
00122 rail_manipulation_msgs::Grasp grasp;
00123 grasp.grasp_pose = pose;
00124 grasp.attempts = possible_grasps[i].getAttempts();
00125 grasp.successes = possible_grasps[i].getSuccesses();
00126 grasp.eef_frame_id = possible_grasps[i].getEefFrameID();
00127 for (size_t j = 0; j < success_rates.size(); j++)
00128 {
00129 if (rate <= success_rates[j])
00130 {
00131 object.grasps.insert(object.grasps.begin() + j, grasp);
00132 success_rates.insert(success_rates.begin() + j, rate);
00133 inserted = true;
00134 break;
00135 }
00136 }
00137
00138 if (!inserted)
00139 {
00140 object.grasps.push_back(grasp);
00141 success_rates.push_back(rate);
00142 }
00143 }
00144 }
00145
00146 return true;
00147 }
00148
00149 double PointCloudRecognizer::scoreRegistration(pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr candidate,
00150 pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr object, tf2::Transform &tf_icp) const
00151 {
00152
00153 pcl::PointCloud<pcl::PointXYZRGB>::Ptr aligned(new pcl::PointCloud<pcl::PointXYZRGB>);
00154 tf_icp = point_cloud_metrics::performICP(candidate, object, aligned);
00155
00156
00157 double overlap, color_error;
00158 point_cloud_metrics::calculateRegistrationMetricOverlap(candidate, aligned, overlap, color_error);
00159 if (overlap < OVERLAP_THRESHOLD)
00160 {
00161 return numeric_limits<double>::infinity();
00162 }
00163
00164
00165 double distance_error = point_cloud_metrics::calculateRegistrationMetricDistanceError(candidate, aligned);
00166
00167
00168 double result = ALPHA * (3.0 * distance_error) + (1.0 - ALPHA) * (color_error / 100.0);
00169 return result;
00170 }
00171
00172 void PointCloudRecognizer::computeGraspList(const tf2::Transform &tf_icp, const geometry_msgs::Point ¢roid,
00173 const vector<graspdb::Grasp> &candidate_grasps, vector<graspdb::Grasp> &grasps) const
00174 {
00175
00176 grasps.clear();
00177
00178
00179 for (size_t i = 0; i < candidate_grasps.size(); i++)
00180 {
00181
00182 tf2::Transform tf_pose = candidate_grasps[i].getGraspPose().toTF2Transform();
00183
00184
00185 grasps.push_back(candidate_grasps[i]);
00186
00187
00188 tf2::Transform result = tf_icp.inverseTimes(tf_pose);
00189
00190
00191 result.getOrigin().setX(result.getOrigin().getX() + centroid.x);
00192 result.getOrigin().setY(result.getOrigin().getY() + centroid.y);
00193 result.getOrigin().setZ(result.getOrigin().getZ() + centroid.z);
00194
00195
00196 grasps[i].setGraspPose(graspdb::Pose(grasps[i].getGraspPose().getRobotFixedFrameID(), result));
00197 }
00198 }