Skip to content

Commit

Permalink
Merge pull request #1115 from jpapon/supervoxel_transform_fix
Browse files Browse the repository at this point in the history
Change default behavior of SupervoxelClustering
  • Loading branch information
taketwo committed Mar 20, 2015
2 parents 815f487 + 43ad1f8 commit 4a4a4f5
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/segmentation/supervoxel_clustering.h>

//VTK include needed for drawing graph lines
#include <vtkPolyLine.h>

// Types
typedef pcl::PointXYZRGBA PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
Expand Down Expand Up @@ -42,7 +45,7 @@ main (int argc, char ** argv)
}


bool use_transform = ! pcl::console::find_switch (argc, argv, "--NT");
bool disable_transform = pcl::console::find_switch (argc, argv, "--NT");

float voxel_resolution = 0.008f;
bool voxel_res_specified = pcl::console::find_switch (argc, argv, "-v");
Expand Down Expand Up @@ -70,7 +73,9 @@ main (int argc, char ** argv)
////// This is how to use supervoxels
////////////////////////////// //////////////////////////////

pcl::SupervoxelClustering<PointT> super (voxel_resolution, seed_resolution, use_transform);
pcl::SupervoxelClustering<PointT> super (voxel_resolution, seed_resolution);
if (disable_transform)
super.setUseSingleCameraTransform (false);
super.setInputCloud (cloud);
super.setColorImportance (color_importance);
super.setSpatialImportance (spatial_importance);
Expand All @@ -90,9 +95,9 @@ main (int argc, char ** argv)
viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE,2.0, "voxel centroids");
viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY,0.95, "voxel centroids");

PointCloudT::Ptr colored_voxel_cloud = super.getColoredVoxelCloud ();
viewer->addPointCloud (colored_voxel_cloud, "colored voxels");
viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY,0.8, "colored voxels");
PointLCloudT::Ptr labeled_voxel_cloud = super.getLabeledVoxelCloud ();
viewer->addPointCloud (labeled_voxel_cloud, "labeled voxels");
viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY,0.8, "labeled voxels");

PointNCloudT::Ptr sv_normal_cloud = super.makeSupervoxelNormalCloud (supervoxel_clusters);
//We have this disabled so graph is easy to see, uncomment to see supervoxel normals
Expand Down
22 changes: 11 additions & 11 deletions doc/tutorials/content/supervoxel_clustering.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,17 @@ We start by defining convenience types in order not to clutter the code.

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 9-14
:lines: 12-17

Then we load the input cloud based on the input argument

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 36-42
:lines: 39-45

Next we check the input arguments and set default values. You can play with the various parameters to see how they affect the supervoxels, but briefly:

- ``--NT`` Disables the single-view transform (this is necessary if you are loading a cloud constructed from more than one viewpoint)
- ``--NT`` Disables the single-view transform (this is the default for unorganized clouds, only affects organized clouds)
- ``-v`` Sets the voxel size, which determines the leaf size of the underlying octree structure (in meters)
- ``-s`` Sets the seeding size, which determines how big the supervoxels will be (in meters)
- ``-c`` Sets the weight for color - how much color will influence the shape of the supervoxels
Expand All @@ -97,17 +97,17 @@ Next we check the input arguments and set default values. You can play with the

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 45-67
:lines: 48-70

We are now ready to setup the supervoxel clustering. We use the class :pcl:`SupervoxelClustering <pcl::SupervoxelClustering>`, which implements the clustering process and give it the parameters.

.. important::

You MUST set use_transform to false if you are using a cloud which doesn't have the camera at (0,0,0). The transform is specifically designed to help improve Kinect data by increasing voxel bin size as distance from the camera increases. If your data is artificial, made from combining multiple clouds from cameras at different viewpoints, or doesn't have the camera at (0,0,0), the transform MUST be set to false.
By default, the algorithm will use a special tranform compressing the depth in Z if your input cloud is organized (eg, from an RGBD sensor like the Kinect). You MUST set use_transform to false if you are using an organized cloud which doesn't have the camera at (0,0,0) and depth in positive Z. The transform is specifically designed to help improve Kinect data by increasing voxel bin size as distance from the camera increases. If your cloud is unorganized, this transform will not be used by default, but can be enabled by using setUseSingleCameraTransform(true).

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 73-77
:lines: 76-82

Then we initialize the data structure which will be used to extract the supervoxels, and run the algorithm. The data structure is a map from labels to shared pointers of :pcl:`Supervoxel <pcl::Supervoxel>` templated on the input point type. Supervoxels have the following fields:

Expand All @@ -118,31 +118,31 @@ Then we initialize the data structure which will be used to extract the supervox

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 79-83
:lines: 84-88

We then load a viewer and use some of the getter functions of :pcl:`SupervoxelClustering <pcl::SupervoxelClustering>` to pull out clouds to display. ``voxel_centroid_cloud`` contains the voxel centroids coming out of the octree (basically the downsampled original cloud), and ``colored_voxel_cloud`` are the voxels colored according to their supervoxel labels (random colors). ``sv_normal_cloud`` contains a cloud of the supervoxel normals, but we don't display it here so that the graph is visible.

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 85-99
:lines: 90-104

Finally, we extract the supervoxel adjacency list (in the form of a multimap of label adjacencies).

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 101-103
:lines: 106-108

Then we iterate through the multimap, creating a point cloud of the centroids of each supervoxel's neighbors.

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 105-120
:lines: 110-125

Then we create a string label for the supervoxel graph we will draw and call ``addSupervoxelConnectionsToViewer``, a drawing helper function implemented later in the tutorial code. The details of ``addSupervoxelConnectionsToViewer`` are beyond the scope of this tutorial, but all it does is draw a star polygon mesh of the supervoxel centroid to all of its neighbors centroids. We need to do this like this because adding individual lines using the ``addLine`` functionality of ``pcl_visualizer`` is too slow for large numbers of lines.

.. literalinclude:: sources/supervoxel_clustering/supervoxel_clustering.cpp
:language: cpp
:lines: 121-127
:lines: 126-132

This results in a supervoxel graph that looks like this for seed size of 0.1m (top) and 0.05m (middle). The bottom is the original cloud, given for reference.:

Expand Down
3 changes: 2 additions & 1 deletion examples/segmentation/example_lccp_segmentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ LCCPSegmentation Parameters: \n\

/// Preparation of Input: Supervoxel Oversegmentation

pcl::SupervoxelClustering<PointT> super (voxel_resolution, seed_resolution, use_single_cam_transform);
pcl::SupervoxelClustering<PointT> super (voxel_resolution, seed_resolution);
super.setUseSingleCameraTransform (use_single_cam_transform);
super.setInputCloud (input_cloud_ptr);
if (has_normals)
super.setNormalCloud (input_normals_ptr);
Expand Down
11 changes: 8 additions & 3 deletions examples/segmentation/example_supervoxels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,9 @@ main (int argc, char ** argv)
////////////////////////////// //////////////////////////////
////////////////////////////// //////////////////////////////

// If we're using the single camera transform no negative z allowed since we use log(z)
if (!disable_transform)
// If the cloud is organized and we haven't disabled the transform we need to
// check that there are no negative z values, since we use log(z)
if (cloud->isOrganized () && !disable_transform)
{
for (PointCloudT::iterator cloud_itr = cloud->begin (); cloud_itr != cloud->end (); ++cloud_itr)
if (cloud_itr->z < 0)
Expand All @@ -279,7 +280,11 @@ main (int argc, char ** argv)
std::cout <<"You can disable the transform with the --NT flag\n";
}

pcl::SupervoxelClustering<PointT> super (voxel_resolution, seed_resolution,!disable_transform);
pcl::SupervoxelClustering<PointT> super (voxel_resolution, seed_resolution);
//If we manually disabled the transform then do so, otherwise the default
//behavior will take place (true for organized, false for unorganized)
if (disable_transform)
super.setUseSingleCameraTransform (false);
super.setInputCloud (cloud);
if (has_normals)
super.setNormalCloud (input_normals);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,32 @@

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT>
pcl::SupervoxelClustering<PointT>::SupervoxelClustering (float voxel_resolution, float seed_resolution, bool use_single_camera_transform) :
pcl::SupervoxelClustering<PointT>::SupervoxelClustering (float voxel_resolution, float seed_resolution) :
resolution_ (voxel_resolution),
seed_resolution_ (seed_resolution),
adjacency_octree_ (),
voxel_centroid_cloud_ (),
color_importance_ (0.1f),
spatial_importance_ (0.4f),
normal_importance_ (1.0f)
normal_importance_ (1.0f),
use_default_transform_behaviour_ (true)
{
adjacency_octree_.reset (new OctreeAdjacencyT (resolution_));
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT>
pcl::SupervoxelClustering<PointT>::SupervoxelClustering (float voxel_resolution, float seed_resolution, bool) :
resolution_ (voxel_resolution),
seed_resolution_ (seed_resolution),
adjacency_octree_ (),
voxel_centroid_cloud_ (),
color_importance_ (0.1f),
spatial_importance_ (0.4f),
normal_importance_ (1.0f),
use_default_transform_behaviour_ (true)
{
adjacency_octree_.reset (new OctreeAdjacencyT (resolution_));
if (use_single_camera_transform)
adjacency_octree_->setTransformFunction (boost::bind (&SupervoxelClustering::transformFunction, this, _1));
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -188,6 +202,10 @@ pcl::SupervoxelClustering<PointT>::prepareForSegmentation ()
//Add the new cloud of data to the octree
//std::cout << "Populating adjacency octree with new cloud \n";
//double prep_start = timer_.getTime ();
if ( (use_default_transform_behaviour_ && input_->isOrganized ())
|| (!use_default_transform_behaviour_ && use_single_camera_transform_))
adjacency_octree_->setTransformFunction (boost::bind (&SupervoxelClustering::transformFunction, this, _1));

adjacency_octree_->addPointsFromInputCloud ();
//double prep_end = timer_.getTime ();
//std::cout<<"Time elapsed populating octree with next frame ="<<prep_end-prep_start<<" ms\n";
Expand Down Expand Up @@ -672,6 +690,14 @@ pcl::SupervoxelClustering<PointT>::setNormalImportance (float val)
normal_importance_ = val;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT> void
pcl::SupervoxelClustering<PointT>::setUseSingleCameraTransform (bool val)
{
use_default_transform_behaviour_ = false;
use_single_camera_transform_ = val;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT> int
pcl::SupervoxelClustering<PointT>::getMaxLabel () const
Expand Down
29 changes: 26 additions & 3 deletions segmentation/include/pcl/segmentation/supervoxel_clustering.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,11 @@ namespace pcl
/** \brief Constructor that sets default values for member variables.
* \param[in] voxel_resolution The resolution (in meters) of voxels used
* \param[in] seed_resolution The average size (in meters) of resulting supervoxels
* \param[in] use_single_camera_transform Set to true if point density in cloud falls off with distance from origin (such as with a cloud coming from one stationary camera), set false if input cloud is from multiple captures from multiple locations.
*/
SupervoxelClustering (float voxel_resolution, float seed_resolution, bool use_single_camera_transform = true);
SupervoxelClustering (float voxel_resolution, float seed_resolution);

PCL_DEPRECATED ("SupervoxelClustering constructor with flag for using the single camera transform is deprecated. Default behavior is now to use the transform for organized clouds, and not use it for unorganized. To force use/disuse of the transform, use the setUseSingleCameraTransform(bool) function.")
SupervoxelClustering (float voxel_resolution, float seed_resolution, bool);

/** \brief This destructor destroys the cloud, normals and search method used for
* finding neighbors. In other words it frees memory.
Expand Down Expand Up @@ -225,6 +227,19 @@ namespace pcl
void
setNormalImportance (float val);

/** \brief Set whether or not to use the single camera transform
* \note By default it will be used for organized clouds, but not for unorganized - this parameter will override that behavior
* The single camera transform scales bin size so that it increases exponentially with depth (z dimension).
* This is done to account for the decreasing point density found with depth when using an RGB-D camera.
* Without the transform, beyond a certain depth adjacency of voxels breaks down unless the voxel size is set to a large value.
* Using the transform allows preserving detail up close, while allowing adjacency at distance.
* The specific transform used here is:
* x /= z; y /= z; z = ln(z);
* This transform is applied when calculating the octree bins in OctreePointCloudAdjacency
*/
void
setUseSingleCameraTransform (bool val);

/** \brief This method launches the segmentation algorithm and returns the supervoxels that were
* obtained during the segmentation.
* \param[out] supervoxel_clusters A map of labels to pointers to supervoxel structures
Expand Down Expand Up @@ -389,7 +404,15 @@ namespace pcl
float spatial_importance_;
/** \brief Importance of similarity in normals for clustering */
float normal_importance_;


/** \brief Whether or not to use the transform compressing depth in Z
* This is only checked if it has been manually set by the user.
* The default behavior is to use the transform for organized, and not for unorganized.
*/
bool use_single_camera_transform_;
/** \brief Whether to use default transform behavior or not */
bool use_default_transform_behaviour_;

/** \brief Internal storage class for supervoxels
* \note Stores pointers to leaves of clustering internal octree,
* \note so should not be used outside of clustering class
Expand Down

0 comments on commit 4a4a4f5

Please sign in to comment.