00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 #include "jsk_pcl_ros/edge_depth_refinement.h"
00037 
00038 #include <pcl/segmentation/sac_segmentation.h>
00039 #include <pcl/filters/extract_indices.h>
00040 #include <pcl/io/io.h>
00041 #include "jsk_recognition_utils/pcl_util.h"
00042 #include <sstream>
00043 
00044 namespace jsk_pcl_ros
00045 {
00046   void EdgeDepthRefinement::onInit()
00047   {
00048     ConnectionBasedNodelet::onInit();
00049 
00051     
00053     pub_indices_ = advertise<jsk_recognition_msgs::ClusterPointIndices>(
00054       *pnh_, "output", 1);
00055     pub_coefficients_ = advertise<jsk_recognition_msgs::ModelCoefficientsArray>(
00056       *pnh_, "output_coefficients", 1);
00057     pub_edges_ = advertise<jsk_recognition_msgs::SegmentArray>(
00058       *pnh_, "output_edges", 1);
00059     pub_outlier_removed_indices_ = advertise<jsk_recognition_msgs::ClusterPointIndices>(
00060       *pnh_, "output_outlier_removed", 1);
00061     pub_outlier_removed_coefficients_ = advertise<jsk_recognition_msgs::ModelCoefficientsArray>(
00062       *pnh_, "output_outlier_removed_coefficients", 1);
00063     pub_outlier_removed_edges_= advertise<jsk_recognition_msgs::SegmentArray>(
00064       *pnh_, "output_outlier_removed_edges", 1);
00066     
00068     srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00069     dynamic_reconfigure::Server<Config>::CallbackType f =
00070       boost::bind (&EdgeDepthRefinement::configCallback, this, _1, _2);
00071     srv_->setCallback (f);
00072 
00073     onInitPostProcess();
00074   }
00075 
00076   void EdgeDepthRefinement::subscribe()
00077   {
00079     
00081     sub_input_.subscribe(*pnh_, "input", 1);
00082     sub_indices_.subscribe(*pnh_, "input_indices", 1);
00083     sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00084     sync_->connectInput(sub_input_, sub_indices_);
00085     sync_->registerCallback(boost::bind(&EdgeDepthRefinement::refine,
00086                                         this, _1, _2));
00087   }
00088 
00089   void EdgeDepthRefinement::unsubscribe()
00090   {
00091     sub_input_.unsubscribe();
00092     sub_indices_.unsubscribe();
00093   }
00094   
00096   
00097   
00098   
00099   
00100   
00101   
00102   
00104   jsk_recognition_utils::Line::Ptr EdgeDepthRefinement::lineFromCoefficients(
00105     const pcl::ModelCoefficients::Ptr coefficients)
00106   {
00107     Eigen::Vector3f p(coefficients->values[0],
00108                       coefficients->values[1],
00109                       coefficients->values[2]);
00110     Eigen::Vector3f d(coefficients->values[3],
00111                       coefficients->values[4],
00112                       coefficients->values[5]);
00113     jsk_recognition_utils::Line::Ptr ret (new jsk_recognition_utils::Line(d, p));
00114     return ret;
00115   }
00116 
00117   boost::tuple<int, int> EdgeDepthRefinement::findMinMaxIndex(
00118     const int width, const int height,
00119     const std::vector<int>& indices)
00120   {
00121     
00122     int min_y_index, max_y_index, min_x_index, max_x_index;
00123     int min_y = INT_MAX;
00124     int min_x = INT_MAX;
00125     int max_y = INT_MIN;
00126     int max_x = INT_MIN;
00127     for (size_t i = 0; i < indices.size(); i++) {
00128       int index = indices[i];
00129       int x = index % width;
00130       int y = index / width;
00131 
00132       if (x > max_x) {
00133         max_x = x;
00134         max_x_index = index;
00135       }
00136       if (x < min_x) {
00137         min_x = x;
00138         min_x_index = index;
00139       }
00140       if (y > max_y) {
00141         max_y = y;
00142         max_y_index = index;
00143       }
00144       if (y < min_y) {
00145         min_y = y;
00146         min_y_index = index;
00147       }
00148     }
00149 
00150     if (min_x_index != max_x_index) {
00151       return boost::make_tuple(
00152         min_x_index, max_x_index);
00153     }
00154     else {
00155       return boost::make_tuple(
00156         min_y_index, max_y_index);
00157     }
00158   }
00159 
00160   
00161   jsk_recognition_utils::Segment::Ptr EdgeDepthRefinement::segmentFromIndices(
00162     const pcl::PointCloud<PointT>::Ptr& cloud,
00163     const std::vector<int>& indices,
00164     const jsk_recognition_utils::Line::Ptr& line)
00165   {
00166     boost::tuple<int, int> min_max
00167       = findMinMaxIndex(cloud->width, cloud->height, indices);
00168     PointT min_point = cloud->points[min_max.get<0>()];
00169     PointT max_point = cloud->points[min_max.get<1>()];
00170     Eigen::Vector3f min_point_f = min_point.getVector3fMap();
00171     Eigen::Vector3f max_point_f = max_point.getVector3fMap();
00172     Eigen::Vector3f min_foot, max_foot;
00173     line->foot(min_point_f, min_foot);
00174     line->foot(max_point_f, max_foot);
00175     jsk_recognition_utils::Segment::Ptr segment (new jsk_recognition_utils::Segment(min_foot, max_foot));
00176     return segment;
00177   }
00178 
00179   void EdgeDepthRefinement::integrateDuplicatedIndices(
00180     const pcl::PointCloud<PointT>::Ptr& cloud,
00181     const std::set<int>& duplicated_set,
00182     const std::vector<pcl::PointIndices::Ptr> all_inliers,
00183     pcl::PointIndices::Ptr& output_indices)
00184   {
00185     std::vector<int> integrated_indices;
00186     for (std::set<int>::iterator it = duplicated_set.begin();
00187          it != duplicated_set.end();
00188          ++it) {
00189       integrated_indices = jsk_recognition_utils::addIndices(all_inliers[*it]->indices,
00190                                       integrated_indices);
00191     }
00192     output_indices->indices = integrated_indices;
00193   }
00194   
00195   void EdgeDepthRefinement::removeDuplicatedEdges(
00196     const pcl::PointCloud<PointT>::Ptr& cloud,
00197     const std::vector<pcl::PointIndices::Ptr> all_inliers,
00198     const std::vector<pcl::ModelCoefficients::Ptr> all_coefficients,
00199     std::vector<pcl::PointIndices::Ptr>& output_inliers,
00200     std::vector<pcl::ModelCoefficients::Ptr>& output_coefficients)
00201   {
00202     if (all_inliers.size() == 0) {
00203       NODELET_ERROR("no edges are specified");
00204       return;
00205     }
00206 
00207     
00208     std::vector<jsk_recognition_utils::Line::Ptr> lines;
00209     std::vector<jsk_recognition_utils::Segment::Ptr> segments;
00210     
00211     for (size_t i = 0; i < all_inliers.size(); i++) {
00212       pcl::PointIndices::Ptr the_inliers = all_inliers[i];
00213       pcl::ModelCoefficients::Ptr the_coefficients = all_coefficients[i];
00214       jsk_recognition_utils::Line::Ptr the_line = lineFromCoefficients(the_coefficients);
00215       jsk_recognition_utils::Segment::Ptr the_segment
00216         = segmentFromIndices(cloud, the_inliers->indices, the_line);
00217       lines.push_back(the_line);
00218       segments.push_back(the_segment);
00219     }
00220 
00222     
00223     
00225     std::map<int, std::vector<int> > duplication_map;
00226     for (size_t i = 0; i < all_inliers.size() - 1; i++) {
00227       duplication_map[i] = std::vector<int>(); 
00228       jsk_recognition_utils::Line::Ptr the_line = lines[i];
00229       jsk_recognition_utils::Segment::Ptr the_segment = segments[i];
00230       for (size_t j = i + 1; j < all_inliers.size(); j++) {
00231         jsk_recognition_utils::Line::Ptr candidate_line = lines[j];
00232         jsk_recognition_utils::Segment::Ptr candidate_segment = segments[j];
00233         Eigen::Vector3f candidate_midpoint;
00234         candidate_segment->midpoint(candidate_midpoint);
00235 
00236         double angle_diff = the_line->angle(*candidate_line);
00237         if (duplication_angle_threshold_ > angle_diff) {
00238           double distance_diff = the_segment->distance(candidate_midpoint);
00239           if (duplication_distance_threshold_ > distance_diff) {
00240             duplication_map[i].push_back(j);
00241           }
00242         }
00243       }
00244     }
00245 
00247     
00249     std::vector<std::set<int> > duplication_set_list;
00250     std::set<int> duplicated_indices;
00251     for (size_t i = 0; i < all_inliers.size(); i++) {
00252       std::vector<int> duplication_list;
00253       if (i < all_inliers.size() - 1) {
00254         duplication_list = duplication_map[i];
00255       }
00256       if (duplicated_indices.find(i) == duplicated_indices.end()) {
00257         if (i == all_inliers.size() - 1 || duplication_list.size() == 0) { 
00258           std::set<int> no_duplication_set;
00259           no_duplication_set.insert(i);
00260           duplication_set_list.push_back(no_duplication_set);
00261           jsk_recognition_utils::addSet<int>(duplicated_indices, no_duplication_set);
00262         }
00263         else { 
00264           std::set<int> new_duplication_set;
00265           jsk_recognition_utils::buildGroupFromGraphMap(duplication_map,
00266                                  i,
00267                                  duplication_list,
00268                                  new_duplication_set);
00269           duplication_set_list.push_back(new_duplication_set);
00270           
00271           jsk_recognition_utils::addSet<int>(duplicated_indices, new_duplication_set);
00272         }
00273       }
00274     }
00275 
00276 
00277     for (size_t i = 0; i < duplication_set_list.size(); i++) {
00278       pcl::PointIndices::Ptr integrated_indices (new pcl::PointIndices);
00279       integrateDuplicatedIndices(cloud, duplication_set_list[i],
00280                                  all_inliers,
00281                                  integrated_indices);
00282       output_inliers.push_back(integrated_indices);
00283       
00284       
00285       pcl::ModelCoefficients::Ptr integrated_coefficients 
00286         = all_coefficients[(*duplication_set_list[i].begin())];
00287       output_coefficients.push_back(integrated_coefficients);
00288     }
00289 
00290     
00291     
00292     
00293     
00294     
00295     
00296     
00297     
00298     
00299     
00300     
00301     
00302     
00303     
00304     
00305     
00306     
00307     
00308     
00309     
00310     
00311     
00312     
00313   }
00314   
00315   void EdgeDepthRefinement::removeOutliers(
00316     const pcl::PointCloud<PointT>::Ptr& cloud,
00317     const std::vector<PCLIndicesMsg>& indices,
00318     std::vector<pcl::PointIndices::Ptr>& output_inliers,
00319     std::vector<pcl::ModelCoefficients::Ptr>& output_coefficients)
00320   {
00321     
00322     
00323     for (size_t i = 0; i < indices.size(); i++) {
00324       std::vector<int> cluster_indices = indices[i].indices;
00325       pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
00326       pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
00327       removeOutliersByLine(cloud, cluster_indices, *inliers, *coefficients);
00328       if (inliers->indices.size() > min_inliers_) {
00329         output_inliers.push_back(inliers);
00330         output_coefficients.push_back(coefficients);
00331       }
00332     }
00333   }
00334   
00335   void EdgeDepthRefinement::removeOutliersByLine(
00336     const pcl::PointCloud<PointT>::Ptr& cloud,
00337     const std::vector<int>& indices,
00338     pcl::PointIndices& inliers,
00339     pcl::ModelCoefficients& coefficients)
00340   {
00341     
00342     
00343     pcl::SACSegmentation<PointT> seg;
00344     seg.setOptimizeCoefficients (true);
00345     seg.setModelType (pcl::SACMODEL_LINE);
00346     seg.setMethodType (pcl::SAC_RANSAC);
00347     seg.setDistanceThreshold (outlier_distance_threshold_);
00348     seg.setInputCloud(cloud);
00349     pcl::PointIndices::Ptr indices_ptr (new pcl::PointIndices);
00350     indices_ptr->indices = indices;
00351     seg.setIndices(indices_ptr);
00352     seg.segment (inliers, coefficients);
00353   }
00354 
00355   void EdgeDepthRefinement::publishIndices(
00356     ros::Publisher& pub,
00357     ros::Publisher& pub_coefficients,
00358     ros::Publisher& pub_edges,
00359     const std::vector<pcl::PointIndices::Ptr> inliers,
00360     const std::vector<pcl::ModelCoefficients::Ptr> coefficients,
00361     const std_msgs::Header& header)
00362   {
00363     jsk_recognition_msgs::ClusterPointIndices output_ros_msg;
00364     jsk_recognition_msgs::ModelCoefficientsArray output_ros_coefficients_msg;
00365     jsk_recognition_msgs::SegmentArray output_ros_edges_msg;
00366     output_ros_msg.header = header;
00367     output_ros_coefficients_msg.header = header;
00368     output_ros_edges_msg.header = header;
00369     for (size_t i = 0; i < inliers.size(); i++) {
00370       PCLIndicesMsg output_indices_msg;
00371       PCLModelCoefficientMsg output_coefficients_msg;
00372       jsk_recognition_msgs::Segment output_edge_msg;
00373       output_indices_msg.header = header;
00374       output_indices_msg.indices = inliers[i]->indices;
00375       output_ros_msg.cluster_indices.push_back(output_indices_msg);
00376 
00377       output_coefficients_msg.header = header;
00378       output_coefficients_msg.values = coefficients[i]->values;
00379       output_ros_coefficients_msg.coefficients.push_back(output_coefficients_msg);
00380 
00381       output_edge_msg.start_point.x = coefficients[i]->values[0] - coefficients[i]->values[3];
00382       output_edge_msg.start_point.y = coefficients[i]->values[1] - coefficients[i]->values[4];
00383       output_edge_msg.start_point.z = coefficients[i]->values[2] - coefficients[i]->values[5];
00384       output_edge_msg.end_point.x = coefficients[i]->values[0] + coefficients[i]->values[3];
00385       output_edge_msg.end_point.y = coefficients[i]->values[1] + coefficients[i]->values[4];
00386       output_edge_msg.end_point.z = coefficients[i]->values[2] + coefficients[i]->values[5];
00387       output_ros_edges_msg.segments.push_back(output_edge_msg);
00388     }
00389     pub.publish(output_ros_msg);
00390     pub_coefficients.publish(output_ros_coefficients_msg);
00391     pub_edges.publish(output_ros_edges_msg);
00392   }
00393 
00394   void EdgeDepthRefinement::configCallback (Config &config, uint32_t level)
00395   {
00396     boost::mutex::scoped_lock lock(mutex_);
00397     outlier_distance_threshold_ = config.outlier_distance_threshold;
00398     min_inliers_ = config.min_inliers;
00399     duplication_angle_threshold_ = config.duplication_angle_threshold;
00400     duplication_distance_threshold_ = config.duplication_distance_threshold;
00401   }
00402   
00403   void EdgeDepthRefinement::refine(
00404     const sensor_msgs::PointCloud2ConstPtr &input,
00405     const jsk_recognition_msgs::ClusterPointIndicesConstPtr &indices)
00406   {
00407     boost::mutex::scoped_lock lock(mutex_);
00408     pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
00409     pcl::fromROSMsg(*input, *cloud);
00410     
00411     std::vector<pcl::PointIndices::Ptr> inliers;
00412     std::vector<pcl::ModelCoefficients::Ptr> coefficients;
00413 
00414     removeOutliers(cloud, indices->cluster_indices, inliers, coefficients);
00415     std::vector<pcl::PointIndices::Ptr> non_duplicated_inliers;
00416     std::vector<pcl::ModelCoefficients::Ptr> non_duplicated_coefficients;
00417     removeDuplicatedEdges(cloud, inliers, coefficients,
00418                           non_duplicated_inliers,
00419                           non_duplicated_coefficients);
00420     publishIndices(pub_outlier_removed_indices_,
00421                    pub_outlier_removed_coefficients_,
00422                    pub_outlier_removed_edges_,
00423                    inliers, coefficients,
00424                    input->header);
00425     publishIndices(pub_indices_,
00426                    pub_coefficients_,
00427                    pub_edges_,
00428                    non_duplicated_inliers,
00429                    non_duplicated_coefficients,
00430                    input->header);
00431   }
00432   
00433 }
00434 
00435 #include <pluginlib/class_list_macros.h>
00436 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::EdgeDepthRefinement, nodelet::Nodelet);