next_best_view.cpp
Go to the documentation of this file.
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   //parameters
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   //objects needed
00068   tf::TransformListener tf_listener_;
00069 
00070   //datasets
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   // Publishes the octree in MarkerArray format so that it can be visualized in rviz
00088   ros::Publisher octree_marker_array_publisher_;
00089   /* The following publisher, even though not required, is used because otherwise rviz
00090    * cannot visualize the MarkerArray format without advertising the Marker format*/
00091   ros::Publisher octree_marker_publisher_;
00092   // Marker array to visualize the octree. It displays the occuplied cells of the octree
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   //get the latest parameters
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   //get the viewpoint (position of laser) from tf
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   //Converting PointCloud2 msg format to pcl pointcloud format in order to read the 3d data
00197   pcl::fromROSMsg(*pointcloud2_msg, pointcloud2_pcl);
00198 
00199   // create or update the octree
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    * assign new points to Leaf Nodes  and cast rays from laser pos to point
00208    */
00209   castRayAndLabel(pointcloud2_pcl, laser_pose);
00210 
00211   /*
00212    * find unknown voxels with free neighbors and add them to a pointcloud
00213    */
00214   pcl::PointCloud<pcl::PointXYZ> border_cloud;
00215   findBorderPoints(border_cloud, pointcloud2_msg->header.frame_id);
00216 
00217   // Create the filtering objects
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   //creating datasets
00224   pcl::PointCloud<pcl::Normal> border_normals;
00225 
00226   //filter out ceiling
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   // tree object used for search
00233   pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointXYZ> > ();
00234 
00235   // Estimate point normals
00236   ne.setSearchMethod(tree);
00237   ne.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (border_cloud));
00238   ne.setRadiusSearch(normal_search_radius_);
00239   //ne.setKSearch(0);
00240   ne.compute(border_normals);
00241 
00242   //filter again to remove spurious NaNs
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   //in pointcloud
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   //and in the normals
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   // tree object used for search
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   // Decompose a region of space into clusters based on the euclidean distance between points, and the normal
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    * compute boundary points from clusters and put them into pose array
00274    */
00275   computeBoundaryPoints(border_cloud, border_normals, clusters, cluster_clouds);
00276 
00277   //publish poses
00278   pose_pub_.publish(nbv_pose_array_);
00279 
00280   //publish border cloud for visualization
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   //publish the clusters for visualization
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   // publish binary octree
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   //Visualization
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   //clear old poses
00325   nbv_pose_array_.poses.clear();
00326 
00327   if (clusters.size() > 0) {
00328     ROS_INFO ("%d clusters found.", (int)clusters.size());
00329     // sort the clusters according to number of points they contain
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       //extract maximum of 3 biggest clusters
00337       if (nc == 3)
00338         break;
00339 
00340       //extract a cluster
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       //extract normals of cluster
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       // find boundary points of cluster
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       //save this cluster pointcloud for visualization
00385       cluster_clouds[nc] = cluster_cloud;
00386 
00387       //pop the just used cluster from indices
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       // Get the nodes along the ray and label them as free
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     // if free voxel -> check for unknown neighbors
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             // add to list of border voxels
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   //Reading from pcl point cloud and saving it into octomap point cloud
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   // Converting from octomap point cloud to octomap graph
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   // Converting from octomap graph to octomap tree (octree)
00484   octree_->insertScan(*scan_node, octree_maxrange_, false);
00485 
00486   octree_->expand();
00487 
00488   //
00489   // create nodes that are unknown
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   //ROS_DEBUG("octree min bounds [%f %f %f]", min(0), min(1), min(2));
00504   //ROS_DEBUG("octree max bounds [%f %f %f]", max(0), max(1), max(2));
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           //ROS_INFO("creating node at [%f %f %f]", centroid(0), centroid(1), centroid(2));
00518           //corresponding node doesn't exist yet -> create it
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     //int cnt = 0;
00530     // get all existing leaves
00531     std::list<octomap::OcTreeVolume> leaves;
00532     octree_->getLeafNodes(leaves);
00533 
00534     //find Leaf Nodes' centroids, assign controid coordinates to Leaf Node
00535     BOOST_FOREACH(octomap::OcTreeVolume vol, leaves) {
00536       //ROS_DEBUG("Leaf Node %d : x = %f y = %f z = %f side length = %f ", cnt++, it1->first.x(), it1->first.y(), it1->first.z(), it1->second);
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   // each array stores all cubes of a different size, one for each depth level:
00557   octree_marker_array_msg_.markers.resize(4);
00558   double lowestRes = octree_->getResolution();
00559   //ROS_INFO_STREAM("lowest resolution: " << lowestRes);
00560 
00561   std::list<octomap::OcTreeVolume> all_cells;
00562   //getting the cells at level 0
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   // occupied cells
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   // free cells
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   // unknown cells
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   // viewpoint
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


next_best_view
Author(s): Felix Ruess
autogenerated on Sun Oct 6 2013 12:11:35