00001 #include <ros/ros.h>
00002 #include <sensor_msgs/PointCloud2.h>
00003
00004 #include <geometry_msgs/PoseArray.h>
00005
00006 #include "octomap/octomap.h"
00007 #include <octomap_ros/OctomapBinary.h>
00008 #include "pcl_to_octree/octree/OcTreePCL.h"
00009 #include "pcl_to_octree/octree/OcTreeNodePCL.h"
00010 #include "pcl_to_octree/octree/OcTreeServerPCL.h"
00011
00012 #include <pcl/io/pcd_io.h>
00013 #include <pcl/point_types.h>
00014 #include <pcl/features/normal_3d.h>
00015 #include <pcl/features/boundary.h>
00016 #include <pcl/segmentation/extract_clusters.h>
00017 #include <pcl/filters/extract_indices.h>
00018 #include <pcl/filters/passthrough.h>
00019
00020 #include <pcl_ros/publisher.h>
00021
00022 #include <tf/transform_listener.h>
00023
00024 #include <visualization_msgs/MarkerArray.h>
00025
00026 #include <vector>
00027
00045 class Nbv
00046 {
00047 protected:
00048 ros::NodeHandle nh_;
00049
00050
00051 std::string input_cloud_topic_;
00052 std::string output_octree_topic_;
00053 std::string output_pose_topic_;
00054 std::string laser_frame_;
00055
00056 double octree_res_, octree_maxrange_;
00057 int level_, free_label_, occupied_label_, unknown_label_;
00058 bool check_centroids_;
00059 bool visualize_octree_;
00060
00061 double normal_search_radius_;
00062 int min_pts_per_cluster_;
00063 double eps_angle_;
00064 double tolerance_;
00065 double boundary_angle_threshold_;
00066
00067
00068 tf::TransformListener tf_listener_;
00069
00070
00071 octomap::OcTreePCL* octree_;
00072 octomap::ScanGraph* octomap_graph_;
00073
00074 octomap::KeyRay ray;
00075
00076 sensor_msgs::PointCloud2 cloud_in_;
00077 geometry_msgs::PoseArray nbv_pose_array_;
00078
00079 ros::Subscriber cloud_sub_;
00080 ros::Publisher octree_pub_;
00081 pcl_ros::Publisher<pcl::PointNormal> border_cloud_pub_;
00082 pcl_ros::Publisher<pcl::PointXYZ> cluster_cloud_pub_;
00083 pcl_ros::Publisher<pcl::PointXYZ> cluster_cloud2_pub_;
00084 pcl_ros::Publisher<pcl::PointXYZ> cluster_cloud3_pub_;
00085 ros::Publisher pose_pub_;
00086
00087
00088 ros::Publisher octree_marker_array_publisher_;
00089
00090
00091 ros::Publisher octree_marker_publisher_;
00092
00093 visualization_msgs::MarkerArray octree_marker_array_msg_;
00094
00095 static bool compareClusters(pcl::PointIndices c1, pcl::PointIndices c2) { return (c1.indices.size() < c2.indices.size()); }
00096
00097 void cloud_cb (const sensor_msgs::PointCloud2ConstPtr& pointcloud2_msg);
00098 void createOctree (pcl::PointCloud<pcl::PointXYZ>& pointcloud2_pcl, octomap::pose6d laser_pose);
00099 void visualizeOctree(const sensor_msgs::PointCloud2ConstPtr& pointcloud2_msg, geometry_msgs::Point viewpoint);
00100 void castRayAndLabel(pcl::PointCloud<pcl::PointXYZ>& cloud, octomap::pose6d origin);
00101 void findBorderPoints(pcl::PointCloud<pcl::PointXYZ>& border_cloud, std::string frame_id);
00102 void computeBoundaryPoints(pcl::PointCloud<pcl::PointXYZ>& border_cloud, pcl::PointCloud<pcl::Normal>& border_normals, std::vector<pcl::PointIndices>& clusters, pcl::PointCloud<pcl::PointXYZ>* cluster_clouds);
00103
00104 void extractClusters (const pcl::PointCloud<pcl::PointXYZ> &cloud,
00105 const pcl::PointCloud<pcl::Normal> &normals,
00106 float tolerance,
00107 const boost::shared_ptr<pcl::KdTree<pcl::PointXYZ> > &tree,
00108 std::vector<pcl::PointIndices> &clusters, double eps_angle,
00109 unsigned int min_pts_per_cluster = 1,
00110 unsigned int max_pts_per_cluster = std::numeric_limits<int>::max ());
00111
00112
00113 public:
00114 Nbv(ros::NodeHandle &anode);
00115 ~Nbv();
00116 };
00117
00118
00119 Nbv::Nbv (ros::NodeHandle &anode) : nh_(anode) {
00120 nh_.param("input_cloud_topic", input_cloud_topic_, std::string("/points2_out"));
00121 nh_.param("output_octree_topic", output_octree_topic_, std::string("/nbv_octree"));
00122 nh_.param("output_pose_topic", output_pose_topic_, std::string("/nbv_pose"));
00123 nh_.param("laser_frame", laser_frame_, std::string("/laser_tilt_link"));
00124 nh_.param("octree_resolution", octree_res_, 0.1);
00125
00126 nh_.param("octree_maxrange", octree_maxrange_, -1.0);
00127 nh_.param("level", level_, 0);
00128 nh_.param("check_centroids", check_centroids_, false);
00129 nh_.param("free_label", free_label_, 0);
00130 nh_.param("occupied_label", occupied_label_, 1);
00131 nh_.param("unknown_label", unknown_label_, -1);
00132 nh_.param("visualize_octree", visualize_octree_, true);
00133
00134 nh_.param("normal_search_radius", normal_search_radius_, 0.6);
00135 nh_.param("min_pts_per_cluster", min_pts_per_cluster_, 10);
00136 nh_.param("eps_angle", eps_angle_, 0.25);
00137 nh_.param("tolerance", tolerance_, 0.3);
00138 nh_.param("boundary_angle_threshold", boundary_angle_threshold_, 2.5);
00139
00140 cloud_sub_ = nh_.subscribe (input_cloud_topic_, 1, &Nbv::cloud_cb, this);
00141 octree_pub_ = nh_.advertise<octomap_ros::OctomapBinary> (output_octree_topic_, 1);
00142 border_cloud_pub_ = pcl_ros::Publisher<pcl::PointNormal> (nh_, "border_cloud", 1);
00143 cluster_cloud_pub_ = pcl_ros::Publisher<pcl::PointXYZ> (nh_, "cluster_cloud", 1);
00144 cluster_cloud2_pub_ = pcl_ros::Publisher<pcl::PointXYZ> (nh_, "cluster_cloud2", 1);
00145 cluster_cloud3_pub_ = pcl_ros::Publisher<pcl::PointXYZ> (nh_, "cluster_cloud3", 1);
00146 pose_pub_ = nh_.advertise<geometry_msgs::PoseArray> (output_pose_topic_, 1);
00147
00148 octree_marker_array_publisher_ = nh_.advertise<visualization_msgs::MarkerArray>("visualization_marker_array", 100);
00149 octree_marker_publisher_ = nh_.advertise<visualization_msgs::Marker>("visualization_marker", 100);
00150
00151 octree_ = NULL;
00152 }
00153
00154 Nbv::~Nbv()
00155 {
00156 ROS_INFO("Shutting down next_best_view node!");
00157
00158 octree_marker_array_publisher_.shutdown();
00159 octree_marker_publisher_.shutdown();
00160 }
00161
00166 void Nbv::cloud_cb (const sensor_msgs::PointCloud2ConstPtr& pointcloud2_msg) {
00167
00168 pcl::PointCloud<pcl::PointXYZ> pointcloud2_pcl;
00169 octomap::point3d octomap_point3d;
00170
00171 ROS_INFO("Received point cloud");
00172
00173
00174 nh_.getParam("normal_search_radius", normal_search_radius_);
00175 nh_.getParam("min_pts_per_cluster", min_pts_per_cluster_);
00176 nh_.getParam("eps_angle", eps_angle_);
00177 nh_.getParam("tolerance", tolerance_);
00178 nh_.getParam("boundary_angle_threshold", boundary_angle_threshold_);
00179
00180
00181 tf::StampedTransform transform;
00182 try {
00183 ros::Time acquisition_time = pointcloud2_msg->header.stamp;
00184 ros::Duration timeout(1.0 / 30);
00185 tf_listener_.waitForTransform(pointcloud2_msg->header.frame_id, laser_frame_, acquisition_time, timeout);
00186 tf_listener_.lookupTransform(pointcloud2_msg->header.frame_id, laser_frame_, acquisition_time, transform);
00187 }
00188 catch (tf::TransformException& ex) {
00189 ROS_WARN("[next_best_view] TF exception:\n%s", ex.what());
00190 }
00191 tf::Point pt = transform.getOrigin();
00192 octomap::pose6d laser_pose (pt.x(), pt.y(), pt.z(),0,0,0);
00193 ROS_INFO("viewpoint [%f %f %f]", pt.x(), pt.y(), pt.z());
00194
00195
00196
00197 pcl::fromROSMsg(*pointcloud2_msg, pointcloud2_pcl);
00198
00199
00200 if (octree_ == NULL) {
00201 octomap_graph_ = new octomap::ScanGraph();
00202 octree_ = new octomap::OcTreePCL(octree_res_);
00203 }
00204 createOctree(pointcloud2_pcl, laser_pose);
00205
00206
00207
00208
00209 castRayAndLabel(pointcloud2_pcl, laser_pose);
00210
00211
00212
00213
00214 pcl::PointCloud<pcl::PointXYZ> border_cloud;
00215 findBorderPoints(border_cloud, pointcloud2_msg->header.frame_id);
00216
00217
00218 pcl::PassThrough<pcl::PointXYZ> pass;
00219 pcl::ExtractIndices<pcl::PointXYZ> extract;
00220 pcl::ExtractIndices<pcl::Normal> nextract;
00221 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
00222
00223
00224 pcl::PointCloud<pcl::Normal> border_normals;
00225
00226
00227 pass.setInputCloud (boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (border_cloud));
00228 pass.setFilterFieldName ("z");
00229 pass.setFilterLimits (0, 2.2);
00230 pass.filter(border_cloud);
00231
00232
00233 pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
00234
00235
00236 ne.setSearchMethod(tree);
00237 ne.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (border_cloud));
00238 ne.setRadiusSearch(normal_search_radius_);
00239
00240 ne.compute(border_normals);
00241
00242
00243 pcl::PointIndices nan_indices;
00244 for (unsigned int i = 0; i < border_normals.points.size(); i++) {
00245 if (isnan(border_normals.points[i].normal[0]))
00246 nan_indices.indices.push_back(i);
00247 }
00248 ROS_INFO("%d NaNs found", (int)nan_indices.indices.size());
00249
00250 extract.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (border_cloud));
00251 extract.setIndices(boost::make_shared<pcl::PointIndices> (nan_indices));
00252 extract.setNegative(true);
00253 extract.filter(border_cloud);
00254 ROS_INFO("%d points in border cloud after filtering and NaN removal", (int)border_cloud.points.size());
00255
00256 nextract.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::Normal> > (border_normals));
00257 nextract.setIndices(boost::make_shared<pcl::PointIndices> (nan_indices));
00258 nextract.setNegative(true);
00259 nextract.filter(border_normals);
00260 ROS_INFO("%d points in normals cloud after NaN removal", (int)border_normals.points.size());
00261
00262
00263 pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree2 = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
00264
00265 tree2->setInputCloud (boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (border_cloud));
00266
00267 std::vector<pcl::PointIndices> clusters;
00268 pcl::extractEuclideanClusters <pcl::PointXYZ, pcl::Normal> (border_cloud, border_normals, tolerance_, tree2, clusters, eps_angle_, min_pts_per_cluster_);
00269
00270 pcl::PointCloud<pcl::PointXYZ> cluster_clouds[3];
00271
00272
00273
00274
00275 computeBoundaryPoints(border_cloud, border_normals, clusters, cluster_clouds);
00276
00277
00278 pose_pub_.publish(nbv_pose_array_);
00279
00280
00281 pcl::PointCloud<pcl::PointNormal> border_pn_cloud;
00282 if (border_cloud.points.size() > 0) {
00283 pcl::concatenateFields(border_cloud, border_normals, border_pn_cloud);
00284 } else {
00285 border_pn_cloud.header.frame_id = border_cloud.header.frame_id;
00286 border_pn_cloud.header.stamp = ros::Time::now();
00287 }
00288 border_cloud_pub_.publish(border_pn_cloud);
00289
00290
00291 for (unsigned int i = 0; i < 3; i++) {
00292 if (cluster_clouds[i].points.size() == 0) {
00293 cluster_clouds[i].header.frame_id = border_cloud.header.frame_id;
00294 cluster_clouds[i].header.stamp = ros::Time::now();
00295 }
00296 }
00297 cluster_cloud_pub_.publish(cluster_clouds[0]);
00298 cluster_cloud2_pub_.publish(cluster_clouds[1]);
00299 cluster_cloud3_pub_.publish(cluster_clouds[2]);
00300
00301
00302 if (0) {
00303 octomap_ros::OctomapBinary octree_msg;
00304 octomap_server::octomapMapToMsg(*octree_, octree_msg);
00305 octree_pub_.publish(octree_msg);
00306 }
00307
00308 ROS_INFO("All computed and published");
00309
00310
00311
00312
00313 if (visualize_octree_)
00314 {
00315 geometry_msgs::Point viewpoint;
00316 viewpoint.x = pt.x();
00317 viewpoint.y = pt.y();
00318 viewpoint.z = pt.z();
00319 visualizeOctree(pointcloud2_msg, viewpoint);
00320 }
00321 }
00322
00323 void Nbv::computeBoundaryPoints(pcl::PointCloud<pcl::PointXYZ>& border_cloud, pcl::PointCloud<pcl::Normal>& border_normals, std::vector<pcl::PointIndices>& clusters, pcl::PointCloud<pcl::PointXYZ>* cluster_clouds) {
00324
00325 nbv_pose_array_.poses.clear();
00326
00327 if (clusters.size() > 0) {
00328 ROS_INFO ("%d clusters found.", (int)clusters.size());
00329
00330 std::sort(clusters.begin(), clusters.end(), compareClusters);
00331
00332 pcl::ExtractIndices<pcl::PointXYZ> extract;
00333 pcl::ExtractIndices<pcl::Normal> nextract;
00334
00335 for (unsigned int nc = 0; nc < clusters.size(); nc++) {
00336
00337 if (nc == 3)
00338 break;
00339
00340
00341 pcl::PointCloud<pcl::PointXYZ> cluster_cloud;
00342 extract.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (border_cloud));
00343 extract.setIndices(boost::make_shared<pcl::PointIndices> (clusters.back()));
00344 extract.setNegative(false);
00345 extract.filter(cluster_cloud);
00346 ROS_INFO ("PointCloud representing the cluster %d: %d data points.", nc, cluster_cloud.width * cluster_cloud.height);
00347
00348
00349 pcl::PointCloud<pcl::Normal> cluster_normals;
00350 nextract.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::Normal> > (border_normals));
00351 nextract.setIndices(boost::make_shared<pcl::PointIndices> (clusters.back()));
00352 nextract.setNegative(false);
00353 nextract.filter(cluster_normals);
00354
00355
00356 pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree3 = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
00357 pcl::PointCloud<pcl::Boundary> boundary_cloud;
00358 pcl::BoundaryEstimation<pcl::PointXYZ, pcl::Normal, pcl::Boundary> be;
00359 be.setSearchMethod(tree3);
00360 be.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (cluster_cloud));
00361 be.setInputNormals(boost::make_shared<pcl::PointCloud<pcl::Normal> > (cluster_normals));
00362 be.setRadiusSearch(.5);
00363 be.angle_threshold_ = boundary_angle_threshold_;
00364 be.compute(boundary_cloud);
00365
00366 geometry_msgs::Pose nbv_pose;
00367 unsigned int nbp = 0;
00368 for (unsigned int i = 0; i < boundary_cloud.points.size(); ++i) {
00369 if (boundary_cloud.points[i].boundary_point) {
00370 nbv_pose.position.x = cluster_cloud.points[i].x;
00371 nbv_pose.position.y = cluster_cloud.points[i].y;
00372 nbv_pose.position.z = cluster_cloud.points[i].z;
00373 btVector3 axis(0, -cluster_normals.points[i].normal[2], cluster_normals.points[i].normal[1]);
00374 btQuaternion quat(axis, axis.length());
00375 geometry_msgs::Quaternion quat_msg;
00376 tf::quaternionTFToMsg(quat, quat_msg);
00377 nbv_pose.orientation = quat_msg;
00378 nbv_pose_array_.poses.push_back(nbv_pose);
00379 nbp++;
00380 }
00381 }
00382 ROS_INFO ("%d boundary points in cluster %d.", nbp, nc);
00383
00384
00385 cluster_clouds[nc] = cluster_cloud;
00386
00387
00388 clusters.pop_back();
00389 }
00390 nbv_pose_array_.header.frame_id = border_cloud.header.frame_id;
00391 nbv_pose_array_.header.stamp = ros::Time::now();
00392 }
00393 else {
00394 ROS_INFO ("No clusters found!");
00395 }
00396 }
00397
00398 void Nbv::castRayAndLabel(pcl::PointCloud<pcl::PointXYZ>& cloud, octomap::pose6d origin) {
00399 octomap::point3d octomap_point3d;
00400
00401 BOOST_FOREACH (const pcl::PointXYZ& pcl_pt, cloud.points) {
00402 octomap_point3d(0) = pcl_pt.x;
00403 octomap_point3d(1) = pcl_pt.y;
00404 octomap_point3d(2) = pcl_pt.z;
00405 octomap::OcTreeNodePCL * octree_end_node = octree_->search(octomap_point3d);
00406 if (octree_end_node != NULL) {
00407
00408 if (octree_->computeRayKeys(origin.trans(), octomap_point3d, ray)) {
00409 for(octomap::KeyRay::iterator it=ray.begin(); it != ray.end(); it++) {
00410 octomap::OcTreeNodePCL * free_node = octree_->search(*it);
00411 if (free_node != NULL) {
00412 if (free_node->getLabel() != occupied_label_)
00413 free_node->setLabel(free_label_);
00414 }
00415 else
00416 ROS_DEBUG("node in ray not found!");
00417 }
00418 }
00419 else {
00420 ROS_DEBUG("could not compute ray from [%f %f %f] to [%f %f %f]", origin.x(), origin.y(), origin.z(), pcl_pt.x, pcl_pt.y, pcl_pt.z);
00421 }
00422 octree_end_node->set3DPointInliers(0);
00423 octree_end_node->setLabel(occupied_label_);
00424 }
00425 else {
00426 ROS_DEBUG("ERROR: node at [%f %f %f] not found", pcl_pt.x, pcl_pt.y, pcl_pt.z);
00427 }
00428 }
00429 }
00430
00431 void Nbv::findBorderPoints(pcl::PointCloud<pcl::PointXYZ>& border_cloud, std::string frame_id) {
00432 border_cloud.header.frame_id = frame_id;
00433 border_cloud.header.stamp = ros::Time::now();
00434 std::list<octomap::OcTreeVolume> leaves;
00435 octree_->getLeafNodes(leaves);
00436 BOOST_FOREACH(octomap::OcTreeVolume vol, leaves) {
00437 octomap::point3d centroid;
00438 centroid(0) = vol.first.x(), centroid(1) = vol.first.y(), centroid(2) = vol.first.z();
00439 octomap::OcTreeNodePCL *octree_node = octree_->search(centroid);
00440
00441
00442 if (octree_node != NULL && octree_node->getLabel() == free_label_) {
00443 for (int i=0; i<3; i++) {
00444 octomap::point3d neighbor_centroid = centroid;
00445 for (int j=-1; j<2; j+=2) {
00446 neighbor_centroid(i) += j * octree_res_;
00447 octomap::OcTreeNodePCL *neighbor = octree_->search(neighbor_centroid);
00448 if (neighbor != NULL && neighbor->getLabel() == unknown_label_) {
00449
00450 pcl::PointXYZ border_pt (centroid.x(), centroid.y(), centroid.z());
00451 border_cloud.points.push_back(border_pt);
00452 break;
00453 }
00454 }
00455 }
00456 }
00457 }
00458 ROS_INFO("%d points in border cloud", (int)border_cloud.points.size());
00459 }
00460
00464 void Nbv::createOctree (pcl::PointCloud<pcl::PointXYZ>& pointcloud2_pcl, octomap::pose6d laser_pose) {
00465
00466 octomap::point3d octomap_3d_point;
00467 octomap::Pointcloud octomap_pointcloud;
00468
00469
00470 BOOST_FOREACH (const pcl::PointXYZ& pt, pointcloud2_pcl.points) {
00471 octomap_3d_point(0) = pt.x;
00472 octomap_3d_point(1) = pt.y;
00473 octomap_3d_point(2) = pt.z;
00474 octomap_pointcloud.push_back(octomap_3d_point);
00475 }
00476
00477
00478 octomap_pointcloud.transform(laser_pose.inv());
00479 octomap::ScanNode* scan_node = octomap_graph_->addNode(&octomap_pointcloud, laser_pose);
00480
00481 ROS_INFO("Number of points in scene graph: %d", octomap_graph_->getNumPoints());
00482
00483
00484 octree_->insertScan(*scan_node, octree_maxrange_, false);
00485
00486 octree_->expand();
00487
00488
00489
00490
00491 octomap::point3d min, max;
00492 double min_x, min_y, min_z;
00493 double max_x, max_y, max_z;
00494 octree_->getMetricMin(min_x, min_y, min_z);
00495 octree_->getMetricMax(max_x, max_y, max_z);
00496 min (0) = (float) min_x;
00497 min (1) = (float) min_y;
00498 min (2) = (float) min_z;
00499 max (0) = (float) max_x;
00500 max (1) = (float) max_y;
00501 max (2) = (float) max_z;
00502
00503
00504
00505
00506 double x,y,z;
00507 for (x = min(0)+octree_res_/2; x < max(0)-octree_res_/2; x+=octree_res_) {
00508 for (y = min(1)+octree_res_/2; y < max(1)-octree_res_/2; y+=octree_res_) {
00509 for (z = min(2)+octree_res_/2; z < max(2)-octree_res_/2; z+=octree_res_) {
00510 octomap::point3d centroid (x, y, z);
00511 if (z > max(2))
00512 ROS_INFO("ahrg node at [%f %f %f]", centroid(0), centroid(1), centroid(2));
00513 octomap::OcTreeNodePCL *octree_node = octree_->search(centroid);
00514 if (octree_node != NULL) {
00515 octree_node->setCentroid(centroid);
00516 } else {
00517
00518
00519 octomap::OcTreeNodePCL *new_node = octree_->updateNode(centroid, false);
00520 new_node->setCentroid(centroid);
00521 new_node->setLabel(unknown_label_);
00522 }
00523 }
00524 }
00525 }
00526
00527
00528 if (check_centroids_) {
00529
00530
00531 std::list<octomap::OcTreeVolume> leaves;
00532 octree_->getLeafNodes(leaves);
00533
00534
00535 BOOST_FOREACH(octomap::OcTreeVolume vol, leaves) {
00536
00537 octomap::point3d centroid;
00538 centroid(0) = vol.first.x(), centroid(1) = vol.first.y(), centroid(2) = vol.first.z();
00539 octomap::OcTreeNodePCL *octree_node = octree_->search(centroid);
00540 if (octree_node != NULL) {
00541 octomap::point3d test_centroid;
00542 test_centroid = octree_node->getCentroid();
00543 if (centroid.distance(test_centroid) > octree_res_/4)
00544 ROS_INFO("node at [%f %f %f] has a wrong centroid: [%f %f %f]", centroid(0), centroid(1), centroid(2), test_centroid(0), test_centroid(1), test_centroid(2));
00545 }
00546 else {
00547 ROS_INFO("node at [%f %f %f] not found", centroid(0), centroid(1), centroid(2));
00548 }
00549 }
00550 }
00551
00552 }
00553
00554
00555 void Nbv::visualizeOctree(const sensor_msgs::PointCloud2ConstPtr& pointcloud2_msg, geometry_msgs::Point viewpoint) {
00556
00557 octree_marker_array_msg_.markers.resize(4);
00558 double lowestRes = octree_->getResolution();
00559
00560
00561 std::list<octomap::OcTreeVolume> all_cells;
00562
00563 octree_->getLeafNodes(all_cells, 0);
00564 BOOST_FOREACH(octomap::OcTreeVolume vol, all_cells)
00565 {
00566 geometry_msgs::Point cube_center;
00567 cube_center.x = vol.first.x();
00568 cube_center.y = vol.first.y();
00569 cube_center.z = vol.first.z();
00570 octomap::point3d octo_point (cube_center.x, cube_center.y, cube_center.z);
00571 octomap::OcTreeNodePCL * node = octree_->search(octo_point);
00572 if (node != NULL) {
00573 if (occupied_label_ == node->getLabel())
00574 octree_marker_array_msg_.markers[0].points.push_back(cube_center);
00575 else if (free_label_ == node->getLabel())
00576 octree_marker_array_msg_.markers[1].points.push_back(cube_center);
00577 else if (unknown_label_ == node->getLabel())
00578 octree_marker_array_msg_.markers[2].points.push_back(cube_center);
00579 }
00580 }
00581
00582 octree_marker_array_msg_.markers[3].points.push_back(viewpoint);
00583
00584
00585 octree_marker_array_msg_.markers[0].ns = "Occupied cells";
00586 octree_marker_array_msg_.markers[0].color.r = 1.0f;
00587 octree_marker_array_msg_.markers[0].color.g = 0.0f;
00588 octree_marker_array_msg_.markers[0].color.b = 0.0f;
00589 octree_marker_array_msg_.markers[0].color.a = 0.5f;
00590
00591
00592 octree_marker_array_msg_.markers[1].ns ="Free cells";
00593 octree_marker_array_msg_.markers[1].color.r = 0.0f;
00594 octree_marker_array_msg_.markers[1].color.g = 1.0f;
00595 octree_marker_array_msg_.markers[1].color.b = 0.0f;
00596 octree_marker_array_msg_.markers[1].color.a = 0.5f;
00597
00598
00599 octree_marker_array_msg_.markers[2].ns = "Unknown cells";
00600 octree_marker_array_msg_.markers[2].color.r = 0.0f;
00601 octree_marker_array_msg_.markers[2].color.g = 0.0f;
00602 octree_marker_array_msg_.markers[2].color.b = 1.0f;
00603 octree_marker_array_msg_.markers[2].color.a = 0.05f;
00604
00605
00606 octree_marker_array_msg_.markers[3].ns = "viewpoint";
00607 octree_marker_array_msg_.markers[3].color.r = 1.0f;
00608 octree_marker_array_msg_.markers[3].color.g = 1.0f;
00609 octree_marker_array_msg_.markers[3].color.b = 0.0f;
00610 octree_marker_array_msg_.markers[3].color.a = 0.8f;
00611
00612 for (unsigned i = 0; i < octree_marker_array_msg_.markers.size(); ++i)
00613 {
00614 octree_marker_array_msg_.markers[i].header.frame_id = pointcloud2_msg->header.frame_id;
00615 octree_marker_array_msg_.markers[i].header.stamp = ros::Time::now();
00616 octree_marker_array_msg_.markers[i].id = i;
00617 octree_marker_array_msg_.markers[i].lifetime = ros::Duration::Duration();
00618 octree_marker_array_msg_.markers[i].type = visualization_msgs::Marker::CUBE_LIST;
00619 octree_marker_array_msg_.markers[i].scale.x = lowestRes;
00620 octree_marker_array_msg_.markers[i].scale.y = lowestRes;
00621 octree_marker_array_msg_.markers[i].scale.z = lowestRes;
00622
00623 if (octree_marker_array_msg_.markers[i].points.size() > 0)
00624 octree_marker_array_msg_.markers[i].action = visualization_msgs::Marker::ADD;
00625 else
00626 octree_marker_array_msg_.markers[i].action = visualization_msgs::Marker::DELETE;
00627 }
00628
00629 octree_marker_array_publisher_.publish(octree_marker_array_msg_);
00630
00631 for (unsigned int i = 0; i < octree_marker_array_msg_.markers.size(); i++)
00632 {
00633 if (!octree_marker_array_msg_.markers[i].points.empty())
00634 {
00635 octree_marker_array_msg_.markers[i].points.clear();
00636 }
00637 }
00638 octree_marker_array_msg_.markers.clear();
00639 }
00640
00641 int main (int argc, char* argv[])
00642 {
00643 ros::init (argc, argv, "next_best_view");
00644 ros::NodeHandle nh("~");
00645 Nbv n (nh);
00646 ROS_INFO("Node up and running...");
00647 ros::spin ();
00648
00649 return (0);
00650 }