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 #define BOOST_PARAMETER_MAX_ARITY 7
00036 #include "jsk_pcl_ros/line_segment_collector.h"
00037 #include "jsk_recognition_utils/pcl_conversion_util.h"
00038 #include "jsk_recognition_utils/pcl_util.h"
00039 #include <pcl/sample_consensus/method_types.h>
00040 #include <pcl/sample_consensus/model_types.h>
00041 #include <pcl/segmentation/sac_segmentation.h>
00042
00043 namespace jsk_pcl_ros
00044 {
00045 LineSegmentCluster::LineSegmentCluster():
00046 delta_(Eigen::Vector3f(0, 0, 0)),
00047 points_(new pcl::PointCloud<pcl::PointXYZ>),
00048 raw_points_(new pcl::PointCloud<pcl::PointXYZ>)
00049 {
00050
00051 }
00052
00053 void LineSegmentCluster::addLineSegmentEWMA(
00054 LineSegment::Ptr segment, const double tau)
00055 {
00056 segments_.push_back(segment);
00057 Eigen::Vector3f new_delta = segment->toSegment()->getDirection();
00058 if (new_delta.dot(delta_) < 0) {
00059 new_delta = - new_delta;
00060 }
00061 delta_ = ((1 - tau) * delta_ + tau * new_delta).normalized();
00062
00063
00064 pcl::PointCloud<pcl::PointXYZ>::Ptr new_cloud = segment->getPoints();
00065 for (size_t i = 0; i < new_cloud->points.size(); i++) {
00066 points_->points.push_back(new_cloud->points[i]);
00067 }
00068
00069 pcl::PointCloud<pcl::PointXYZ>::Ptr new_raw_cloud = segment->getRawPoints();
00070 for (size_t i = 0; i < new_raw_cloud->points.size(); i++) {
00071 raw_points_->points.push_back(new_raw_cloud->points[i]);
00072 }
00073 }
00074
00075 pcl::PointCloud<pcl::PointXYZ>::Ptr LineSegmentCluster::getPoints()
00076 {
00077 return points_;
00078 }
00079
00080 pcl::PointCloud<pcl::PointXYZ>::Ptr LineSegmentCluster::getRawPoints()
00081 {
00082 return raw_points_;
00083 }
00084
00085 void LineSegmentCluster::removeBefore(const ros::Time& stamp)
00086 {
00087 bool removed = false;
00088 for (std::vector<LineSegment::Ptr>::iterator it = segments_.begin();
00089 it != segments_.end(); ) {
00090 if (((*it)->header.stamp - stamp).toSec() < 0) {
00091 it = segments_.erase(it);
00092 removed = true;
00093 }
00094 else {
00095 ++it;
00096 }
00097 }
00098 if (removed) {
00099
00100 points_.reset(new pcl::PointCloud<pcl::PointXYZ>);
00101
00102 raw_points_.reset(new pcl::PointCloud<pcl::PointXYZ>);
00103 for (std::vector<LineSegment::Ptr>::iterator it = segments_.begin();
00104 it != segments_.end(); ++it) {
00105 {
00106 pcl::PointCloud<pcl::PointXYZ>::Ptr segment_points = (*it)->getPoints();
00107 for (size_t i = 0; i < segment_points->points.size(); i++) {
00108 points_->points.push_back(segment_points->points[i]);
00109 }
00110 }
00111 {
00112 pcl::PointCloud<pcl::PointXYZ>::Ptr segment_points = (*it)->getRawPoints();
00113 for (size_t i = 0; i < segment_points->points.size(); i++) {
00114 raw_points_->points.push_back(segment_points->points[i]);
00115 }
00116 }
00117 }
00118 }
00119 }
00120
00121 bool LineSegmentCluster::isEmpty()
00122 {
00123 return segments_.size() == 0;
00124 }
00125
00126 void LineSegmentCollector::onInit()
00127 {
00128 DiagnosticNodelet::onInit();
00129 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> > (*pnh_);
00130 dynamic_reconfigure::Server<Config>::CallbackType f =
00131 boost::bind (&LineSegmentCollector::configCallback, this, _1, _2);
00132 srv_->setCallback (f);
00133
00134 if (!pnh_->getParam("fixed_frame_id", fixed_frame_id_)) {
00135 NODELET_ERROR("no ~fixed_frame_id is specified");
00136 return;
00137 }
00138
00139 std::string rotate_type_str;
00140 pnh_->param("rotate_type", rotate_type_str, std::string("tilt_two_way"));
00141 if (rotate_type_str == "tilt") {
00142 rotate_type_ = ROTATION_TILT;
00143 }
00144 else if (rotate_type_str == "tilt_two_way") {
00145 rotate_type_ = ROTATION_TILT_TWO_WAY;
00146 }
00147 else if (rotate_type_str == "spindle") {
00148 rotate_type_ = ROTATION_SPINDLE;
00149 }
00150 else {
00151 NODELET_ERROR("unknown ~rotate_type: %s", rotate_type_str.c_str());
00152 return;
00153 }
00154
00155 pub_point_cloud_
00156 = advertise<sensor_msgs::PointCloud2>(*pnh_, "output/cloud", 1);
00157 pub_inliers_ = advertise<jsk_recognition_msgs::ClusterPointIndices>(*pnh_, "output/inliers", 1);
00158 pub_coefficients_
00159 = advertise<jsk_recognition_msgs::ModelCoefficientsArray>(*pnh_, "output/coefficients", 1);
00160 pub_polygons_
00161 = advertise<jsk_recognition_msgs::PolygonArray>(*pnh_, "output/polygons", 1);
00162 debug_pub_inliers_before_plane_
00163 = advertise<jsk_recognition_msgs::ClusterPointIndices>(
00164 *pnh_, "debug/connect_segments/inliers", 1);
00165
00166 onInitPostProcess();
00167 }
00168
00169 void LineSegmentCollector::configCallback(Config &config, uint32_t level)
00170 {
00171 boost::mutex::scoped_lock lock(mutex_);
00172 ewma_tau_ = config.ewma_tau;
00173 segment_connect_normal_threshold_ = config.segment_connect_normal_threshold;
00174 outlier_threshold_ = config.outlier_threshold;
00175 }
00176
00177 void LineSegmentCollector::subscribe()
00178 {
00179 sub_input_.subscribe(*pnh_, "input", 1);
00180 sub_indices_.subscribe(*pnh_, "input_indices", 1);
00181 sub_coefficients_.subscribe(*pnh_, "input_coefficients", 1);
00182 sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00183 sync_->connectInput(sub_input_, sub_indices_, sub_coefficients_);
00184 sync_->registerCallback(boost::bind(&LineSegmentCollector::collect,
00185 this, _1, _2, _3));
00186 sub_trigger_ = pnh_->subscribe("trigger", 1,
00187 &LineSegmentCollector::triggerCallback, this);
00188 }
00189
00190 void LineSegmentCollector::unsubscribe()
00191 {
00192 sub_input_.unsubscribe();
00193 sub_indices_.unsubscribe();
00194 sub_coefficients_.unsubscribe();
00195 sub_trigger_.shutdown();
00196 }
00197
00198 void LineSegmentCollector::cleanupBuffers(
00199 const ros::Time& stamp)
00200 {
00201 pointclouds_buffer_.removeBefore(stamp);
00202 indices_buffer_.removeBefore(stamp);
00203 coefficients_buffer_.removeBefore(stamp);
00204 segments_buffer_.removeBefore(stamp);
00205 for (std::vector<LineSegmentCluster::Ptr>::iterator it = segment_clusters_.begin();
00206 it != segment_clusters_.end();) {
00207 (*it)->removeBefore(stamp);
00208 if ((*it)->isEmpty()) {
00209 it = segment_clusters_.erase(it);
00210 }
00211 else {
00212 ++it;
00213 }
00214 }
00215 }
00216
00217 void LineSegmentCollector::triggerCallback(
00218 const jsk_recognition_msgs::TimeRange::ConstPtr& trigger)
00219 {
00220 boost::mutex::scoped_lock lock(mutex_);
00221 time_range_ = trigger;
00222 cleanupBuffers(time_range_->start);
00223 }
00224
00225 void LineSegmentCollector::publishBeforePlaneSegmentation(
00226 const std_msgs::Header& header,
00227 const pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
00228 const std::vector<pcl::PointIndices::Ptr>& connected_indices)
00229 {
00230 sensor_msgs::PointCloud2 ros_cloud;
00231 pcl::toROSMsg(*cloud, ros_cloud);
00232 ros_cloud.header = header;
00233 pub_point_cloud_.publish(ros_cloud);
00234 jsk_recognition_msgs::ClusterPointIndices ros_indices;
00235 ros_indices.header = header;
00236 ros_indices.cluster_indices
00237 = pcl_conversions::convertToROSPointIndices(connected_indices, header);
00238 debug_pub_inliers_before_plane_.publish(ros_indices);
00239 }
00240
00241 LineSegmentCluster::Ptr LineSegmentCollector::lookupNearestSegment(
00242 LineSegment::Ptr segment)
00243 {
00244 int max_index = -1;
00245 double max_dot = - DBL_MAX;
00246 for (size_t i = 0; i < segment_clusters_.size(); i++) {
00247 LineSegmentCluster::Ptr cluster = segment_clusters_[i];
00248 Eigen::Vector3f delta_cluster = cluster->getDelta();
00249 Eigen::Vector3f delta = segment->toSegment()->getDirection();
00250 double delta_dot = std::abs(delta_cluster.dot(delta));
00251 if (delta_dot > segment_connect_normal_threshold_) {
00252 if (max_dot < delta_dot) {
00253 max_dot = delta_dot;
00254 max_index = i;
00255 }
00256 }
00257
00258
00259
00260
00261
00262 }
00263 if (max_index == -1) {
00264
00265 return LineSegmentCluster::Ptr();
00266 }
00267 else {
00268
00269 return segment_clusters_[max_index];
00270 }
00271 }
00272
00273 void LineSegmentCollector::collectFromBuffers(
00274 const std_msgs::Header& header,
00275 std::vector<LineSegment::Ptr> new_segments)
00276 {
00277 for (size_t i = 0; i < new_segments.size(); i++) {
00278 LineSegment::Ptr segment = new_segments[i];
00279 LineSegmentCluster::Ptr cluster = lookupNearestSegment(segment);
00280 if (cluster) {
00281 cluster->addLineSegmentEWMA(segment, ewma_tau_);
00282 }
00283 else {
00284 cluster.reset(new LineSegmentCluster());
00285 cluster->addLineSegmentEWMA(segment, 1.0);
00286 segment_clusters_.push_back(cluster);
00287 }
00288 }
00289
00290 pcl::PointCloud<pcl::PointXYZ>::Ptr
00291 connected_cloud(new pcl::PointCloud<pcl::PointXYZ>);
00292 std::vector<pcl::PointIndices::Ptr> connected_indices;
00293 std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr > clouds_list;
00294 for (size_t i = 0; i < segment_clusters_.size(); i++) {
00295 LineSegmentCluster::Ptr cluster = segment_clusters_[i];
00296 pcl::PointIndices::Ptr current_indices (new pcl::PointIndices);
00297 pcl::PointCloud<pcl::PointXYZ>::Ptr current_cloud
00298 = cluster->getRawPoints();
00299 for (size_t j = 0; j < current_cloud->points.size(); j++) {
00300 current_indices->indices.push_back(connected_cloud->points.size() + j);
00301 }
00302 connected_indices.push_back(current_indices);
00303 clouds_list.push_back(current_cloud);
00304 *connected_cloud = *connected_cloud + *current_cloud;
00305 }
00306
00307 publishBeforePlaneSegmentation(
00308 header,
00309 connected_cloud,
00310 connected_indices);
00311 }
00312
00313 void LineSegmentCollector::publishResult(
00314 const std_msgs::Header& header,
00315 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
00316 std::vector<pcl::ModelCoefficients::Ptr> all_coefficients,
00317 std::vector<pcl::PointIndices::Ptr> all_indices)
00318 {
00319 jsk_recognition_msgs::ClusterPointIndices ros_indices;
00320 ros_indices.header = header;
00321 ros_indices.cluster_indices
00322 = pcl_conversions::convertToROSPointIndices(all_indices,
00323 header);
00324 pub_inliers_.publish(ros_indices);
00325 jsk_recognition_msgs::ModelCoefficientsArray ros_coefficients;
00326 ros_coefficients.header = header;
00327 ros_coefficients.coefficients
00328 = pcl_conversions::convertToROSModelCoefficients(
00329 all_coefficients,
00330 header);
00331 pub_coefficients_.publish(ros_coefficients);
00332 jsk_recognition_msgs::PolygonArray ros_polygon;
00333 ros_polygon.header = header;
00334 for (size_t i = 0; i < all_indices.size(); i++) {
00335 jsk_recognition_utils::ConvexPolygon::Ptr convex
00336 = jsk_recognition_utils::convexFromCoefficientsAndInliers<pcl::PointXYZ>(
00337 cloud, all_indices[i], all_coefficients[i]);
00338 geometry_msgs::PolygonStamped polygon_stamped;
00339 polygon_stamped.header = header;
00340 polygon_stamped.polygon = convex->toROSMsg();
00341 ros_polygon.polygons.push_back(polygon_stamped);
00342 }
00343 pub_polygons_.publish(ros_polygon);
00344 }
00345
00346 void LineSegmentCollector::collect(
00347 const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
00348 const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& indices_msg,
00349 const jsk_recognition_msgs::ModelCoefficientsArray::ConstPtr& coefficients_msg)
00350 {
00351 boost::mutex::scoped_lock lock(mutex_);
00352
00353 pointclouds_buffer_.push_back(cloud_msg);
00354 indices_buffer_.push_back(indices_msg);
00355 coefficients_buffer_.push_back(coefficients_msg);
00356 pcl::PointCloud<pcl::PointXYZ>::Ptr
00357 input_cloud(new pcl::PointCloud<pcl::PointXYZ>);
00358 pcl::fromROSMsg(*cloud_msg, *input_cloud);
00359
00360 std::vector<pcl::PointIndices::Ptr> input_indices
00361 = pcl_conversions::convertToPCLPointIndices(indices_msg->cluster_indices);
00362 std::vector<pcl::ModelCoefficients::Ptr> input_coefficients
00363 = pcl_conversions::convertToPCLModelCoefficients(
00364 coefficients_msg->coefficients);
00365 std::vector<LineSegment::Ptr> new_segments;
00366 for (size_t i = 0; i < indices_msg->cluster_indices.size(); i++) {
00367 LineSegment::Ptr segment (new LineSegment(cloud_msg->header,
00368 input_indices[i],
00369 input_coefficients[i],
00370 input_cloud));
00371 segments_buffer_.push_back(segment);
00372 new_segments.push_back(segment);
00373 }
00374 collectFromBuffers(cloud_msg->header, new_segments);
00375 }
00376
00377 }
00378
00379 #include <pluginlib/class_list_macros.h>
00380 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::LineSegmentCollector, nodelet::Nodelet);