00001
00064
00065
00066
00067
00068
00069 #include <sstream>
00070 #include <fstream>
00071
00072
00073 #include <ros/ros.h>
00074 #include <message_filters/subscriber.h>
00075 #include <message_filters/synchronizer.h>
00076 #include <message_filters/sync_policies/exact_time.h>
00077 #include <actionlib/server/simple_action_server.h>
00078 #include <dynamic_reconfigure/server.h>
00079 #include <pcl/io/io.h>
00080 #include <pcl/io/pcd_io.h>
00081 #include <pcl/point_types.h>
00082 #include <pcl_ros/point_cloud.h>
00083 #include <pcl/PointIndices.h>
00084 #include <eigen_conversions/eigen_msg.h>
00085
00086
00087 #include <cob_table_object_cluster/table_object_cluster_nodeletConfig.h>
00088 #include <cob_3d_mapping_common/polygon.h>
00089 #include <cob_3d_mapping_common/ros_msg_conversions.h>
00090
00091
00092
00093
00094 #include <cob_3d_mapping_msgs/GetPointMap.h>
00095 #include <cob_3d_mapping_msgs/SetBoundingBoxes.h>
00096 #include <cob_3d_mapping_msgs/ShapeArray.h>
00097 #include <cob_perception_msgs/PointCloud2Array.h>
00098 #include <cob_object_detection_msgs/Detection.h>
00099 #include <cob_object_detection_msgs/DetectionArray.h>
00100 #include <cob_vision_utils/ros_msg_conversions.h>
00101 #include <visualization_msgs/Marker.h>
00102
00103
00104 #include <boost/timer.hpp>
00105 #include <Eigen/StdVector>
00106
00107 #include "cob_table_object_cluster/table_object_cluster.h"
00108 #include "cob_3d_mapping_msgs/TableObjectClusterAction.h"
00109
00110 #include <cob_3d_mapping_common/stop_watch.h>
00111 #include <pcl/filters/extract_indices.h>
00112 #include <pcl_conversions/pcl_conversions.h>
00113
00114 using namespace cob_table_object_cluster;
00115 using namespace cob_3d_mapping;
00116
00117
00118
00119
00120 class TableObjectClusterNode
00121 {
00122 public:
00123 typedef pcl::PointXYZ Point;
00124 typedef pcl::PointCloud<Point> PointCloud;
00125 typedef message_filters::sync_policies::ExactTime<PointCloud, cob_3d_mapping_msgs::ShapeArray > MySyncPolicy;
00126
00127 TableObjectClusterNode()
00128 : as_(0)
00129 , ctr_(0)
00130 , enable_action_mode_(false)
00131 , last_pc_(new PointCloud)
00132 {
00133 config_server_.setCallback(boost::bind(&TableObjectClusterNode::dynReconfCallback, this, _1, _2));
00134
00135
00136 pc_sub_.subscribe(n_,"point_cloud",1);
00137 sa_sub_.subscribe(n_,"shape_array",1);
00138 sync_ = boost::make_shared <message_filters::Synchronizer<MySyncPolicy> >(100);
00139 sync_->connectInput(pc_sub_, sa_sub_);
00140 sync_->registerCallback(boost::bind(&TableObjectClusterNode::topicCallback, this, _1, _2));
00141
00142
00143 bba_pub_ = n_.advertise<cob_object_detection_msgs::DetectionArray>("bounding_box_array", 1);
00144 marker_pub_ = n_.advertise<visualization_msgs::Marker>("bb_marker",100);
00145 object_cluster_pub_ = n_.advertise<cob_perception_msgs::PointCloud2Array>("cluster_array",1);
00146
00147
00148
00149 set_known_objects_server_ = n_.advertiseService("set_known_objects", &TableObjectClusterNode::setKnownObjects, this);
00150 }
00151
00152
00153 ~TableObjectClusterNode()
00154 {
00156 if(as_) delete as_;
00157 }
00158
00166 void
00167 dynReconfCallback(table_object_cluster_nodeletConfig &config, uint32_t level)
00168 {
00169 save_to_file_ = config.save;
00170 file_path_ = config.file_path;
00171
00172
00173
00174
00175 enable_action_mode_ = config.enable_action_mode;
00176 if(enable_action_mode_)
00177 {
00178 std::cout << "action mode not supported" << std::endl;
00179
00180
00181 }
00182 toc.setPrismHeight(config.height_min, config.height_max);
00183 toc.setClusterParams(config.min_cluster_size, config.cluster_tolerance);
00184 }
00185
00186 bool
00187 setKnownObjects(cob_3d_mapping_msgs::SetBoundingBoxes::Request& req, cob_3d_mapping_msgs::SetBoundingBoxes::Response& res)
00188 {
00189 known_objects_.clear();
00190 for(unsigned int i=0; i<req.bounding_boxes.detections.size(); i++)
00191 {
00192 BoundingBox bb;
00193 bb.min_pt = Eigen::Vector4f(-req.bounding_boxes.detections[i].bounding_box_lwh.x,
00194 -req.bounding_boxes.detections[i].bounding_box_lwh.y, 0, 1.0);
00195 bb.max_pt = Eigen::Vector4f(req.bounding_boxes.detections[i].bounding_box_lwh.x,
00196 req.bounding_boxes.detections[i].bounding_box_lwh.y,
00197 req.bounding_boxes.detections[i].bounding_box_lwh.z, 1.0);
00198 Eigen::Affine3d tf;
00199 tf::poseMsgToEigen(req.bounding_boxes.detections[i].pose.pose , tf);
00200 bb.pose = tf.cast<float>();
00201 known_objects_.push_back(bb);
00202 }
00203 return true;
00204 }
00205
00206 void
00207 compute(cob_object_detection_msgs::DetectionArray& bba,
00208 cob_perception_msgs::PointCloud2Array& pca)
00209 {
00210 pcl::PointCloud<Point>::Ptr pc_red(new pcl::PointCloud<Point>);
00211 toc.removeKnownObjects(last_pc_, known_objects_, pc_red);
00212
00213 toc.setInputCloud(pc_red);
00214 for(size_t i=0; i<last_sa_->shapes.size(); ++i)
00215 {
00216
00217 pcl::PointCloud<Point>::Ptr hull(new pcl::PointCloud<Point>);
00218 shape2hull<Point>(last_sa_->shapes[i], *hull);
00219
00220 pcl::PointIndices::Ptr pc_roi(new pcl::PointIndices);
00221 PrecisionStopWatch sw;
00222 sw.precisionStart();
00223
00224
00225 toc.extractTableRoi(hull, *pc_roi);
00226 ROS_INFO("ROI took %f seconds", sw.precisionStop());
00227 ROS_INFO("ROI has %d points", pc_roi->indices.size());
00228 if(!pc_roi->indices.size()) return;
00229
00230 std::stringstream ss;
00231 if(save_to_file_)
00232 {
00233 ss << file_path_ << "/pc.pcd";
00234 pcl::io::savePCDFileASCII (ss.str(), *last_pc_);
00235 ss.str("");
00236 ss.clear();
00237 ss << file_path_ << "/hull.pcd";
00238 pcl::io::savePCDFileASCII (ss.str(), *hull);
00239 ss.str("");
00240 ss.clear();
00241 ss << file_path_ << "/table_roi.pcd";
00242 PointCloud roi;
00243 pcl::ExtractIndices<Point> extract_roi;
00244 extract_roi.setInputCloud (last_pc_);
00245 extract_roi.setIndices (pc_roi);
00246 extract_roi.filter (roi);
00247 pcl::io::savePCDFileASCII (ss.str(), roi);
00248 ss.str("");
00249 ss.clear();
00250 }
00251
00252 std::vector<PointCloud::Ptr> object_clusters;
00253 std::vector<pcl::PointIndices> object_cluster_indices;
00254 sw.precisionStart();
00255 toc.extractClusters(pc_roi, object_clusters, object_cluster_indices);
00256 ROS_INFO("extract clusters took %f seconds", sw.precisionStop());
00257 sw.precisionStart();
00258 pca.segments.clear();
00259 pcl_conversions::fromPCL(last_pc_->header, pca.header);
00260
00261
00262 Eigen::Vector3f normal(last_sa_->shapes[i].params[0],
00263 last_sa_->shapes[i].params[1],
00264 last_sa_->shapes[i].params[2]);
00265 Eigen::Vector3f point(last_sa_->shapes[i].pose.position.x,
00266 last_sa_->shapes[i].pose.position.y,
00267 last_sa_->shapes[i].pose.position.z);
00268
00269 bba.detections.clear();
00270 pcl_conversions::fromPCL(last_pc_->header, bba.header);
00271
00272
00273 pca.segments.resize(object_clusters.size());
00274 for(unsigned int j=0; j<object_clusters.size(); j++)
00275 {
00276 Eigen::Vector3f pos;
00277 Eigen::Quaternion<float> rot;
00278 Eigen::Vector3f size;
00279
00280 toc.calculateBoundingBox(last_pc_, object_cluster_indices[j], normal, point, pos, rot, size);
00281
00282 bba.detections.push_back(cob_object_detection_msgs::Detection());
00283 pcl_conversions::fromPCL(last_pc_->header, bba.detections.back().header);
00284
00285
00286 bba.detections.back().label = "Object Cluster";
00287 bba.detections.back().detector = "BoundingBoxDetector";
00288 bba.detections.back().score = 0;
00289
00290 pcl_conversions::fromPCL(last_pc_->header, bba.detections.back().pose.header);
00291
00292
00293 cob_perception_common::EigenToROSMsg(pos,rot,bba.detections.back().pose.pose);
00294 cob_perception_common::EigenToROSMsg(size, bba.detections.back().bounding_box_lwh);
00295
00296 pcl::toROSMsg(*object_clusters[j], pca.segments[j]);
00297 pcl_conversions::fromPCL(last_pc_->header, pca.segments[j].header);
00298
00299
00300
00301 if(save_to_file_)
00302 {
00303 ss << file_path_ << "/cl_" << j << ".pcd";
00304 pcl::io::savePCDFileASCII (ss.str(), *object_clusters[j]);
00305 ss.str("");
00306 ss.clear();
00307
00308
00309
00310
00311
00312
00313 }
00314 }
00315 ROS_INFO("BB took %f seconds", sw.precisionStop());
00316 ROS_INFO("Computed %d bounding boxes", object_clusters.size());
00317 }
00318 }
00319
00320
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 void
00372 topicCallback(const PointCloud::ConstPtr& pc, const cob_3d_mapping_msgs::ShapeArray::ConstPtr& sa)
00373 {
00374
00375
00376 *last_pc_ = *pc;
00377 last_sa_ = sa;
00378
00379 ROS_INFO("Saved new PointCloud and %d potential tables", sa->shapes.size());
00380
00381 if(enable_action_mode_) { return; }
00382
00383 cob_object_detection_msgs::DetectionArray bba;
00384 cob_perception_msgs::PointCloud2Array pca;
00385 compute(bba, pca);
00386 publishMarker(bba);
00387 bba_pub_.publish(bba);
00388 object_cluster_pub_.publish(pca);
00389 }
00390
00398 void
00399 publishMarker(cob_object_detection_msgs::DetectionArray& bba)
00400 {
00401 for(unsigned int i=0; i<bba.detections.size(); i++)
00402 {
00403 visualization_msgs::Marker marker;
00404 cob_perception_common::boundingBoxToMarker(bba.detections[i], marker);
00405
00406 marker.lifetime = ros::Duration();
00407 marker.header.frame_id = bba.header.frame_id;
00408 marker.id = i;
00409
00410 marker_pub_.publish(marker);
00411 }
00412 }
00413
00414 void
00415 deleteMarker()
00416 {
00417 for( unsigned int i=0; i<ctr_; i++)
00418 {
00419 visualization_msgs::Marker marker;
00420 marker.action = visualization_msgs::Marker::DELETE;
00421 marker.id = i;
00422 marker_pub_.publish(marker);
00423 }
00424 }
00425
00426
00427 ros::NodeHandle n_;
00428
00429
00430 protected:
00431 actionlib::SimpleActionServer<cob_3d_mapping_msgs::TableObjectClusterAction>* as_;
00432
00433 ros::ServiceServer set_known_objects_server_;
00434 ros::Publisher bba_pub_;
00435 ros::Publisher marker_pub_;
00436 ros::Publisher object_cluster_pub_;
00437 boost::shared_ptr<message_filters::Synchronizer<MySyncPolicy> > sync_;
00438 message_filters::Subscriber<PointCloud> pc_sub_;
00439 message_filters::Subscriber<cob_3d_mapping_msgs::ShapeArray> sa_sub_;
00440 dynamic_reconfigure::Server<table_object_cluster_nodeletConfig> config_server_;
00441
00442 boost::mutex mutex_;
00443
00444 TableObjectCluster<Point> toc;
00445 unsigned int ctr_;
00446
00447 bool save_to_file_;
00448 std::string file_path_;
00449
00450
00451
00452
00453 bool enable_action_mode_;
00454
00455 PointCloud::Ptr last_pc_;
00456 cob_3d_mapping_msgs::ShapeArray::ConstPtr last_sa_;
00457 std::vector<BoundingBox> known_objects_;
00458 };
00459
00460
00461 int main (int argc, char** argv)
00462 {
00463 ros::init (argc, argv, "table_object_cluster_node");
00464
00465 TableObjectClusterNode toc;
00466
00467 ros::Rate loop_rate(10);
00468 while (ros::ok())
00469 {
00470 ros::spinOnce ();
00471 loop_rate.sleep();
00472 }
00473 }
00474