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_pcl_ros/pcl_conversion_util.h"
00038 #include "jsk_pcl_ros/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 JSK_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 JSK_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
00167 void LineSegmentCollector::configCallback(Config &config, uint32_t level)
00168 {
00169 boost::mutex::scoped_lock lock(mutex_);
00170 ewma_tau_ = config.ewma_tau;
00171 segment_connect_normal_threshold_ = config.segment_connect_normal_threshold;
00172 outlier_threshold_ = config.outlier_threshold;
00173 }
00174
00175 void LineSegmentCollector::subscribe()
00176 {
00177 sub_input_.subscribe(*pnh_, "input", 1);
00178 sub_indices_.subscribe(*pnh_, "input_indices", 1);
00179 sub_coefficients_.subscribe(*pnh_, "input_coefficients", 1);
00180 sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00181 sync_->connectInput(sub_input_, sub_indices_, sub_coefficients_);
00182 sync_->registerCallback(boost::bind(&LineSegmentCollector::collect,
00183 this, _1, _2, _3));
00184 sub_trigger_ = pnh_->subscribe("trigger", 1,
00185 &LineSegmentCollector::triggerCallback, this);
00186 }
00187
00188 void LineSegmentCollector::unsubscribe()
00189 {
00190 sub_input_.unsubscribe();
00191 sub_indices_.unsubscribe();
00192 sub_coefficients_.unsubscribe();
00193 sub_trigger_.shutdown();
00194 }
00195
00196 void LineSegmentCollector::updateDiagnostic(
00197 diagnostic_updater::DiagnosticStatusWrapper &stat)
00198 {
00199
00200 }
00201
00202 void LineSegmentCollector::cleanupBuffers(
00203 const ros::Time& stamp)
00204 {
00205 pointclouds_buffer_.removeBefore(stamp);
00206 indices_buffer_.removeBefore(stamp);
00207 coefficients_buffer_.removeBefore(stamp);
00208 segments_buffer_.removeBefore(stamp);
00209 for (std::vector<LineSegmentCluster::Ptr>::iterator it = segment_clusters_.begin();
00210 it != segment_clusters_.end();) {
00211 (*it)->removeBefore(stamp);
00212 if ((*it)->isEmpty()) {
00213 it = segment_clusters_.erase(it);
00214 }
00215 else {
00216 ++it;
00217 }
00218 }
00219 }
00220
00221 void LineSegmentCollector::triggerCallback(
00222 const jsk_recognition_msgs::TimeRange::ConstPtr& trigger)
00223 {
00224 boost::mutex::scoped_lock lock(mutex_);
00225 time_range_ = trigger;
00226 cleanupBuffers(time_range_->start);
00227 }
00228
00229 void LineSegmentCollector::publishBeforePlaneSegmentation(
00230 const std_msgs::Header& header,
00231 const pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
00232 const std::vector<pcl::PointIndices::Ptr>& connected_indices)
00233 {
00234 sensor_msgs::PointCloud2 ros_cloud;
00235 pcl::toROSMsg(*cloud, ros_cloud);
00236 ros_cloud.header = header;
00237 pub_point_cloud_.publish(ros_cloud);
00238 jsk_recognition_msgs::ClusterPointIndices ros_indices;
00239 ros_indices.header = header;
00240 ros_indices.cluster_indices
00241 = pcl_conversions::convertToROSPointIndices(connected_indices, header);
00242 debug_pub_inliers_before_plane_.publish(ros_indices);
00243 }
00244
00245 LineSegmentCluster::Ptr LineSegmentCollector::lookupNearestSegment(
00246 LineSegment::Ptr segment)
00247 {
00248 int max_index = -1;
00249 double max_dot = - DBL_MAX;
00250 for (size_t i = 0; i < segment_clusters_.size(); i++) {
00251 LineSegmentCluster::Ptr cluster = segment_clusters_[i];
00252 Eigen::Vector3f delta_cluster = cluster->getDelta();
00253 Eigen::Vector3f delta = segment->toSegment()->getDirection();
00254 double delta_dot = std::abs(delta_cluster.dot(delta));
00255 if (delta_dot > segment_connect_normal_threshold_) {
00256 if (max_dot < delta_dot) {
00257 max_dot = delta_dot;
00258 max_index = i;
00259 }
00260 }
00261
00262
00263
00264
00265
00266 }
00267 if (max_index == -1) {
00268
00269 return LineSegmentCluster::Ptr();
00270 }
00271 else {
00272
00273 return segment_clusters_[max_index];
00274 }
00275 }
00276
00277 void LineSegmentCollector::collectFromBuffers(
00278 const std_msgs::Header& header,
00279 std::vector<LineSegment::Ptr> new_segments)
00280 {
00281 for (size_t i = 0; i < new_segments.size(); i++) {
00282 LineSegment::Ptr segment = new_segments[i];
00283 LineSegmentCluster::Ptr cluster = lookupNearestSegment(segment);
00284 if (cluster) {
00285 cluster->addLineSegmentEWMA(segment, ewma_tau_);
00286 }
00287 else {
00288 cluster.reset(new LineSegmentCluster());
00289 cluster->addLineSegmentEWMA(segment, 1.0);
00290 segment_clusters_.push_back(cluster);
00291 }
00292 }
00293
00294 pcl::PointCloud<pcl::PointXYZ>::Ptr
00295 connected_cloud(new pcl::PointCloud<pcl::PointXYZ>);
00296 std::vector<pcl::PointIndices::Ptr> connected_indices;
00297 std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr > clouds_list;
00298 for (size_t i = 0; i < segment_clusters_.size(); i++) {
00299 LineSegmentCluster::Ptr cluster = segment_clusters_[i];
00300 pcl::PointIndices::Ptr current_indices (new pcl::PointIndices);
00301 pcl::PointCloud<pcl::PointXYZ>::Ptr current_cloud
00302 = cluster->getRawPoints();
00303 for (size_t j = 0; j < current_cloud->points.size(); j++) {
00304 current_indices->indices.push_back(connected_cloud->points.size() + j);
00305 }
00306 connected_indices.push_back(current_indices);
00307 clouds_list.push_back(current_cloud);
00308 *connected_cloud = *connected_cloud + *current_cloud;
00309 }
00310
00311 publishBeforePlaneSegmentation(
00312 header,
00313 connected_cloud,
00314 connected_indices);
00315 }
00316
00317 void LineSegmentCollector::publishResult(
00318 const std_msgs::Header& header,
00319 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,
00320 std::vector<pcl::ModelCoefficients::Ptr> all_coefficients,
00321 std::vector<pcl::PointIndices::Ptr> all_indices)
00322 {
00323 jsk_recognition_msgs::ClusterPointIndices ros_indices;
00324 ros_indices.header = header;
00325 ros_indices.cluster_indices
00326 = pcl_conversions::convertToROSPointIndices(all_indices,
00327 header);
00328 pub_inliers_.publish(ros_indices);
00329 jsk_recognition_msgs::ModelCoefficientsArray ros_coefficients;
00330 ros_coefficients.header = header;
00331 ros_coefficients.coefficients
00332 = pcl_conversions::convertToROSModelCoefficients(
00333 all_coefficients,
00334 header);
00335 pub_coefficients_.publish(ros_coefficients);
00336 jsk_recognition_msgs::PolygonArray ros_polygon;
00337 ros_polygon.header = header;
00338 for (size_t i = 0; i < all_indices.size(); i++) {
00339 ConvexPolygon::Ptr convex
00340 = convexFromCoefficientsAndInliers<pcl::PointXYZ>(
00341 cloud, all_indices[i], all_coefficients[i]);
00342 geometry_msgs::PolygonStamped polygon_stamped;
00343 polygon_stamped.header = header;
00344 polygon_stamped.polygon = convex->toROSMsg();
00345 ros_polygon.polygons.push_back(polygon_stamped);
00346 }
00347 pub_polygons_.publish(ros_polygon);
00348 }
00349
00350 void LineSegmentCollector::collect(
00351 const sensor_msgs::PointCloud2::ConstPtr& cloud_msg,
00352 const jsk_recognition_msgs::ClusterPointIndices::ConstPtr& indices_msg,
00353 const jsk_recognition_msgs::ModelCoefficientsArray::ConstPtr& coefficients_msg)
00354 {
00355 boost::mutex::scoped_lock lock(mutex_);
00356
00357 pointclouds_buffer_.push_back(cloud_msg);
00358 indices_buffer_.push_back(indices_msg);
00359 coefficients_buffer_.push_back(coefficients_msg);
00360 pcl::PointCloud<pcl::PointXYZ>::Ptr
00361 input_cloud(new pcl::PointCloud<pcl::PointXYZ>);
00362 pcl::fromROSMsg(*cloud_msg, *input_cloud);
00363
00364 std::vector<pcl::PointIndices::Ptr> input_indices
00365 = pcl_conversions::convertToPCLPointIndices(indices_msg->cluster_indices);
00366 std::vector<pcl::ModelCoefficients::Ptr> input_coefficients
00367 = pcl_conversions::convertToPCLModelCoefficients(
00368 coefficients_msg->coefficients);
00369 std::vector<LineSegment::Ptr> new_segments;
00370 for (size_t i = 0; i < indices_msg->cluster_indices.size(); i++) {
00371 LineSegment::Ptr segment (new LineSegment(cloud_msg->header,
00372 input_indices[i],
00373 input_coefficients[i],
00374 input_cloud));
00375 segments_buffer_.push_back(segment);
00376 new_segments.push_back(segment);
00377 }
00378 collectFromBuffers(cloud_msg->header, new_segments);
00379 }
00380
00381 }
00382
00383 #include <pluginlib/class_list_macros.h>
00384 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::LineSegmentCollector, nodelet::Nodelet);