00001
00012
00013 #include "rail_recognition/PointCloudMetrics.h"
00014
00015
00016 #include <pcl_conversions/pcl_conversions.h>
00017
00018
00019 #include <pcl/common/transforms.h>
00020 #include <pcl/filters/extract_indices.h>
00021 #include <pcl/kdtree/kdtree_flann.h>
00022 #include <pcl/registration/icp.h>
00023
00024 using namespace std;
00025 using namespace rail::pick_and_place;
00026
00027 void point_cloud_metrics::rosPointCloud2ToPCLPointCloud(const sensor_msgs::PointCloud2 in,
00028 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &out)
00029 {
00030 pcl::PCLPointCloud2 converter;
00031 pcl_conversions::toPCL(in, converter);
00032 pcl::fromPCLPointCloud2(converter, *out);
00033 }
00034
00035 void point_cloud_metrics::pclPointCloudToROSPointCloud2(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &in,
00036 sensor_msgs::PointCloud2 &out)
00037 {
00038
00039 pcl::PCLPointCloud2 converter;
00040 pcl::toPCLPointCloud2(*in, converter);
00041
00042 pcl_conversions::fromPCL(converter, out);
00043 }
00044
00045 void point_cloud_metrics::transformToOrigin(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00046 const geometry_msgs::Point ¢roid)
00047 {
00048
00049 Eigen::Matrix4f tf;
00050 tf << 1, 0, 0, -centroid.x,
00051 0, 1, 0, -centroid.y,
00052 0, 0, 1, -centroid.z,
00053 0, 0, 0, 1;
00054
00055
00056 pcl::transformPointCloud(*pc, *pc, tf);
00057 }
00058
00059 void point_cloud_metrics::transformToOrigin(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc)
00060 {
00061
00062 geometry_msgs::Point centroid = point_cloud_metrics::computeCentroid(pc);
00063
00064 point_cloud_metrics::transformToOrigin(pc, centroid);
00065 }
00066
00067 void point_cloud_metrics::transformToOrigin(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00068 vector<graspdb::Grasp> &grasps, const geometry_msgs::Point ¢roid)
00069 {
00070
00071 point_cloud_metrics::transformToOrigin(pc, centroid);
00072
00073
00074 for (size_t i = 0; i < grasps.size(); i++)
00075 {
00076 graspdb::Position &position = grasps[i].getGraspPose().getPosition();
00077 position.setX(position.getX() - centroid.x);
00078 position.setY(position.getY() - centroid.y);
00079 position.setZ(position.getZ() - centroid.z);
00080 }
00081 }
00082
00083 void point_cloud_metrics::transformToOrigin(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00084 vector<graspdb::Grasp> &grasps)
00085 {
00086
00087 geometry_msgs::Point centroid = point_cloud_metrics::computeCentroid(pc);
00088
00089 point_cloud_metrics::transformToOrigin(pc, grasps, centroid);
00090 }
00091
00092 void point_cloud_metrics::filterPointCloudOutliers(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00093 const double filter_outlier_search_radius, const double filter_outlier_min_num_neighbors)
00094 {
00095
00096 pcl::KdTreeFLANN<pcl::PointXYZRGB> search_tree;
00097 search_tree.setInputCloud(pc);
00098 vector<int> indices;
00099 vector<float> distances;
00100
00101
00102 pcl::IndicesPtr to_keep(new vector<int>);
00103 for (size_t i = 0; i < pc->size(); i++)
00104 {
00105
00106 int neighbors = search_tree.radiusSearch(pc->at(i), filter_outlier_search_radius, indices, distances);
00107 if (neighbors >= filter_outlier_min_num_neighbors)
00108 {
00109 to_keep->push_back(i);
00110 }
00111 }
00112
00113
00114 pcl::ExtractIndices<pcl::PointXYZRGB> extract;
00115 extract.setInputCloud(pc);
00116 extract.setIndices(to_keep);
00117 extract.filter(*pc);
00118 }
00119
00120 void point_cloud_metrics::filterRedundantPoints(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00121 const double filter_redundant_search_radius)
00122 {
00123
00124 if (pc->size() > 0)
00125 {
00126
00127 pcl::KdTreeFLANN<pcl::PointXYZRGB> search_tree;
00128 search_tree.setInputCloud(pc);
00129
00130
00131 for (int i = ((int) pc->size()) - 1; i >= 0; i--)
00132 {
00133
00134 vector<int> indices;
00135 vector<float> distances;
00136 int neighbors = search_tree.radiusSearch(pc->at(i), filter_redundant_search_radius, indices, distances);
00137 if (neighbors >= 2)
00138 {
00139
00140 pc->erase(pc->begin() + i);
00141 }
00142 }
00143 }
00144 }
00145
00146 geometry_msgs::Point point_cloud_metrics::computeCentroid(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc)
00147 {
00148
00149 Eigen::Vector4f centroid;
00150 pcl::compute3DCentroid(*pc, centroid);
00151 geometry_msgs::Point ros_centroid;
00152 ros_centroid.x = centroid[0];
00153 ros_centroid.y = centroid[1];
00154 ros_centroid.z = centroid[2];
00155
00156 return ros_centroid;
00157 }
00158
00159 double point_cloud_metrics::calculateRegistrationMetricDistanceError(
00160 const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &base, const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &target)
00161 {
00162
00163 pcl::KdTreeFLANN<pcl::PointXYZRGB> search_tree;
00164 search_tree.setInputCloud(base);
00165
00166
00167 double score = 0;
00168 for (size_t i = 0; i < target->size(); i++)
00169 {
00170 vector<int> indices;
00171 vector<float> distances;
00172 search_tree.nearestKSearch(target->at(i), 1, indices, distances);
00173 score += (double) distances[0];
00174 }
00175
00176 return score;
00177 }
00178
00179 void point_cloud_metrics::calculateAvgColors(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc, double &avg_r,
00180 double &avg_g, double &avg_b)
00181 {
00182
00183 avg_r = 0;
00184 avg_g = 0;
00185 avg_b = 0;
00186 for (size_t i = 0; i < pc->size(); i++)
00187 {
00188 const pcl::PointXYZRGB &point = pc->at(i);
00189 avg_r += point.r;
00190 avg_g += point.g;
00191 avg_b += point.b;
00192 }
00193
00194
00195 avg_r /= (double) pc->size();
00196 avg_g /= (double) pc->size();
00197 avg_b /= (double) pc->size();
00198 }
00199
00200 double point_cloud_metrics::calculateStdDevColors(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc,
00201 double &std_dev_r, double &std_dev_g, double &std_dev_b)
00202 {
00203
00204 double avg_r, avg_g, avg_b;
00205 point_cloud_metrics::calculateAvgColors(pc, avg_r, avg_g, avg_b);
00206 point_cloud_metrics::calculateStdDevColors(pc, std_dev_r, std_dev_g, std_dev_b, avg_r, avg_g, avg_b);
00207 }
00208
00209 double point_cloud_metrics::calculateStdDevColors(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc,
00210 double &std_dev_r, double &std_dev_g, double &std_dev_b, const double avg_r, const double avg_g, const double avg_b)
00211 {
00212 double variance_r = 0;
00213 double variance_g = 0;
00214 double variance_b = 0;
00215 for (size_t i = 0; i < pc->size(); i++)
00216 {
00217 const pcl::PointXYZRGB &point = pc->at(i);
00218 variance_r += pow(point.r - avg_r, 2);
00219 variance_g += pow(point.g - avg_r, 2);
00220 variance_b += pow(point.b - avg_r, 2);
00221 }
00222 variance_r /= (double) pc->size();
00223 variance_g /= (double) pc->size();
00224 variance_b /= (double) pc->size();
00225
00226 std_dev_r = sqrt(variance_r);
00227 std_dev_g = sqrt(variance_g);
00228 std_dev_b = sqrt(variance_b);
00229 }
00230
00231 void point_cloud_metrics::calculateRegistrationMetricOverlap(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &base,
00232 const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &target, double &overlap, double &color_error,
00233 const double metric_overlap_search_radius)
00234 {
00235
00236 pcl::KdTreeFLANN<pcl::PointXYZRGB> search_tree;
00237 search_tree.setInputCloud(base);
00238
00239
00240 double score = 0;
00241 double error = 0;
00242 for (size_t i = 0; i < target->size(); i++)
00243 {
00244
00245 vector<int> indices;
00246 vector<float> distances;
00247 const pcl::PointXYZRGB &search_point = target->at(i);
00248
00249 int neighbors = search_tree.radiusSearch(search_point, metric_overlap_search_radius, indices, distances);
00250
00251 if (neighbors > 0)
00252 {
00253 score++;
00254
00255 double rgb_distance = 0;
00256 for (size_t j = 0; j < indices.size(); j++)
00257 {
00258 const pcl::PointXYZRGB &point = base->at(indices[j]);
00259 rgb_distance += sqrt(pow(search_point.r - point.r, 2) + pow(search_point.g - point.g, 2) +
00260 pow(search_point.b - point.b, 2));
00261 }
00262
00263 rgb_distance /= neighbors;
00264 error += rgb_distance;
00265 }
00266 }
00267
00268
00269 color_error = error / score;
00270 overlap = score / (double) target->size();
00271 }
00272
00273 bool point_cloud_metrics::classifyMerge(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &base,
00274 const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &target)
00275 {
00276
00277 double overlap, color_error;
00278 point_cloud_metrics::calculateRegistrationMetricOverlap(base, target, overlap, color_error);
00279
00280 double distance_error = point_cloud_metrics::calculateRegistrationMetricDistanceError(base, target);
00281
00282
00283
00284
00285
00286 return distance_error <= .347063 && color_error <= 113.569;
00287 }
00288
00289 tf2::Transform point_cloud_metrics::performICP(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &target,
00290 const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &source, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &result)
00291 {
00292
00293 pcl::IterativeClosestPoint<pcl::PointXYZRGB, pcl::PointXYZRGB> icp;
00294 icp.setInputSource(source);
00295 icp.setInputTarget(target);
00296
00297 icp.align(*result);
00298
00299
00300 Eigen::Matrix4f transform = icp.getFinalTransformation();
00301
00302
00303 tf2::Matrix3x3 rotation(transform(0, 0), transform(0, 1), transform(0, 2),
00304 transform(1, 0), transform(1, 1), transform(1, 2),
00305 transform(2, 0), transform(2, 1), transform(2, 2));
00306 tf2::Vector3 translation(transform(0, 3), transform(1, 3), transform(2, 3));
00307 tf2::Transform tf_icp(rotation, translation);
00308 return tf_icp;
00309 }