Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve pointcloud visualization with colormaps #1581

Merged
merged 4 commits into from
Jun 8, 2016

Conversation

aecins
Copy link
Contributor

@aecins aecins commented Apr 4, 2016

This pull request addresses #1574. The following functionality is added:

  • Can control which colormap is used to visualize the cloud
  • Can control the range of the colormap used to visualize the cloud
  • JET, HSV and GREY colormaps are generated the same way as the ones for meshes.
  • Added BLUE2RED colormap

Here is a minimal example code to test the new functionality.
If the maintainers agree to these changes I would also like to update the colormaps for mesh visualization.

Here is an example of a pointcloud of a bicycle helmet visualized using different colormaps:
hsv_auto
hsv_0-0 1
b2r_0-0 1

@aecins aecins changed the title [WIP] Improve pointcloud visualization with colormaps Improve pointcloud visualization with colormaps Apr 4, 2016
* \note The list of available colormaps can be found in \ref pcl::visualization::LookUpTableRepresentationProperties.
*/
PCL_EXPORTS bool
getColormapLUT (int colormap_type, vtkSmartPointer<vtkLookupTable> &table);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use enum type LookUpTableRepresentationProperties here for clarity?

@taketwo
Copy link
Member

taketwo commented Jun 6, 2016

Apart from the commented lines looks good to me.

@VictorLamoine
Copy link
Contributor

VictorLamoine commented Jun 6, 2016

👍 in general, I'm glad my work inspired you to solve this issue.

The only problem of this PR is that it duplicates the color map generation code (pcl_visualizer.cpp#L1644-L1672).

Can you change pcl_visualizer.cpp so that it calls pcl::visualization::getColormapLUT (which is now in common.cpp)?

@aecins
Copy link
Contributor Author

aecins commented Jun 6, 2016

Thanks for looking at the code @taketwo and @VictorLamoine. I have made the changes that you have suggested.
@VictorLamoine, the only thing is that I did not check if setShapeRenderingProperties works correctly after the change. I could not figure out how to colormap a mesh. Do you have sample code for it?

@VictorLamoine
Copy link
Contributor

VictorLamoine commented Jun 6, 2016

Here is an example:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(pcl-color_plane_distances)

find_package(PCL 1.8.0 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (color_plane_distances color_plane_distances.cpp)
target_link_libraries (color_plane_distances ${PCL_LIBRARIES})
#include <iostream>

#include <pcl/console/parse.h>
#include <pcl/point_cloud.h>
#include <pcl/common/centroid.h>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/sample_consensus/sac_model_plane.h>
#include <pcl/visualization/pcl_visualizer.h>

/** @brief PCL point object */
typedef pcl::PointXYZ PointT;

/** @brief PCL Point cloud object */
typedef pcl::PointCloud<PointT> PointCloudT;

bool mesh_1_change_LUT = false;
bool mesh_2_change_LUT = false;

void
keyboardEventOccurred (const pcl::visualization::KeyboardEvent& event,
                       void* nothing)
{
  if (event.getKeySym () == "a" && event.keyDown ())
    mesh_1_change_LUT = true;

  if (event.getKeySym () == "b" && event.keyDown ())
    mesh_2_change_LUT = true;
}

int
main (int argc,
      char *argv[])
{
  // Parse the command line arguments for mesh files
  std::vector<int> ply_file_indices = pcl::console::parse_file_extension_argument (argc, argv, ".ply");
  std::vector<int> stl_file_indices = pcl::console::parse_file_extension_argument (argc, argv, ".stl");

  if (ply_file_indices.size () != 0 && stl_file_indices.size () != 0)
  {
    PCL_ERROR("Please provide two meshes in the same format (PLY or STL).\n");
    return (-1);
  }

  pcl::PolygonMesh mesh_1, mesh_2;
  if (ply_file_indices.size () != 0)
  {
    if (pcl::io::loadPolygonFilePLY (argv[ply_file_indices[0]], mesh_1) == 0 ||
        pcl::io::loadPolygonFilePLY (argv[ply_file_indices[1]], mesh_2) == 0 )
    {
      PCL_ERROR("Failed to read mesh file\n");
      return -1;
    }
  }
  else
  {
    if (pcl::io::loadPolygonFileSTL (argv[stl_file_indices[0]], mesh_1) == 0 ||
        pcl::io::loadPolygonFileSTL (argv[stl_file_indices[1]], mesh_2) == 0 )
    {
      PCL_ERROR("Failed to read mesh file\n");
      return -1;
    }
  }

  // Segment plane
  PointCloudT::Ptr cloud_1 (new PointCloudT),
                   cloud_2 (new PointCloudT);
  pcl::fromPCLPointCloud2(mesh_1.cloud, *cloud_1);
  pcl::fromPCLPointCloud2(mesh_2.cloud, *cloud_2);

  pcl::ModelCoefficients::Ptr plane_1 (new pcl::ModelCoefficients),
                              plane_2 (new pcl::ModelCoefficients);
  plane_1->values.resize (4);
  plane_2->values.resize (4);
  pcl::PointIndices::Ptr inliers_plane (new pcl::PointIndices);

  pcl::SACSegmentation<PointT> seg;
  seg.setOptimizeCoefficients (true);
  seg.setMethodType (pcl::SAC_RANSAC);
  seg.setModelType (pcl::SACMODEL_PLANE);
  seg.setDistanceThreshold (.01f);
  seg.setInputCloud (cloud_1);
  seg.segment (*inliers_plane, *plane_1);

  if (inliers_plane->indices.size () == 0)
  {
    PCL_ERROR ("Could not estimate a planar model for the given dataset.\n");
    return (-1);
  }

  seg.setInputCloud (cloud_2);
  seg.segment (*inliers_plane, *plane_2);

  if (inliers_plane->indices.size () == 0)
  {
    PCL_ERROR ("Could not estimate a planar model for the given dataset.\n");
    return (-1);
  }

  //std::cout << "Model coefficients (plane 1)\n" << *plane_1 << std::endl;
  //std::cout << "Model coefficients (plane 2)\n" << *plane_2 << std::endl;

  // Compute point to plane distances
  vtkSmartPointer<vtkFloatArray> mesh_distances_1 = vtkSmartPointer<vtkFloatArray>::New ();
  size_t i = 0;
  for (PointCloudT::iterator cloud_it (cloud_1->begin ()); cloud_it != cloud_1->end (); ++cloud_it)
  {
    double distance;
    distance = pcl::pointToPlaneDistanceSigned (*cloud_it, plane_1->values[0], plane_1->values[1],  plane_1->values[2], plane_1->values[3]);
    mesh_distances_1->InsertTuple1 (i, distance);
    i++;
  }

  vtkSmartPointer<vtkFloatArray> mesh_distances_2 = vtkSmartPointer<vtkFloatArray>::New ();
  i = 0;
  for (PointCloudT::iterator cloud_it (cloud_2->begin ()); cloud_it != cloud_2->end (); ++cloud_it)
  {
    double distance;
    distance = pcl::pointToPlaneDistanceSigned (*cloud_it, plane_2->values[0], plane_2->values[1],  plane_2->values[2], plane_2->values[3]);
    mesh_distances_2->InsertTuple1 (i, distance);
    i++;
  }

  // Color mesh distances from the plane
  vtkSmartPointer<vtkPolyData> poly_data_1 = vtkSmartPointer<vtkPolyData>::New ();
  pcl::io::mesh2vtk (mesh_1, poly_data_1);
  poly_data_1->GetPointData ()->SetScalars (mesh_distances_1);

  vtkSmartPointer<vtkPolyData> poly_data_2 = vtkSmartPointer<vtkPolyData>::New ();
  pcl::io::mesh2vtk (mesh_2, poly_data_2);
  poly_data_2->GetPointData ()->SetScalars (mesh_distances_2);

  // Display
  pcl::visualization::PCLVisualizer viewer;
  //viewer.addPolygonMesh (mesh_1, "mesh_1");
  //viewer.addPolygonMesh (mesh_2, "mesh_2");

  viewer.addModelFromPolyData (poly_data_1, "mesh_1");
  viewer.addModelFromPolyData (poly_data_2, "mesh_2");
  viewer.addCoordinateSystem(10);
  viewer.registerKeyboardCallback (&keyboardEventOccurred, (void*) NULL);
  viewer.resetCamera ();

  int mesh_1_lut_color (1),
      mesh_2_lut_color (1);
  while (!viewer.wasStopped ())
  {
    viewer.spinOnce ();
    // The user pressed "a" or "b" :
    if (mesh_1_change_LUT)
    {
      viewer.setLookUpTableID ("mesh_1");
      mesh_1_change_LUT = false;
      mesh_1_lut_color > 4 ? mesh_1_lut_color = 1 : mesh_1_lut_color++;
      switch (mesh_1_lut_color)
      {
        case 1:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_JET, "mesh_1");
          break;
        case 2:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_JET_INVERSE, "mesh_1");
          break;
        case 3:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_HSV, "mesh_1");
          break;
        case 4:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_HSV_INVERSE, "mesh_1");
          break;
        default:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_GREY, "mesh_1");
          break;
      }
    }
    if (mesh_2_change_LUT)
    {
      viewer.setLookUpTableID ("mesh_2");
      mesh_2_change_LUT = false;
      mesh_2_lut_color > 4 ? mesh_2_lut_color = 1 : mesh_2_lut_color++;
      switch (mesh_2_lut_color)
      {
        case 1:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_JET, "mesh_2");
          break;
        case 2:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_JET_INVERSE, "mesh_2");
          break;
        case 3:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_HSV, "mesh_2");
          break;
        case 4:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_HSV_INVERSE, "mesh_2");
          break;
        default:
          viewer.setShapeRenderingProperties (pcl::visualization::PCL_VISUALIZER_LUT, pcl::visualization::PCL_VISUALIZER_LUT_GREY, "mesh_2");
          break;
      }
    }
  }
  return 0;
}
/color_plane_distances ocean_1.ply ocean_2.ply 

Press a and b to change the color map.

@aecins
Copy link
Contributor Author

aecins commented Jun 6, 2016

Thanks for the code! Everything works as expected. Here is the data visualized using the BLUE2RED colormap.

ocean

@VictorLamoine
Copy link
Contributor

👍 perfect

@taketwo
Copy link
Member

taketwo commented Jun 8, 2016

👍

@Jaykob
Copy link

Jaykob commented Sep 11, 2018

Could somebody please provide some usage examples?
The provided code examples aren't available anymore and I didn't find any other examples...

@VictorLamoine
Copy link
Contributor

@Jaykob I have updated an old comment to add the code:
#1581 (comment)

I did not test this code with the latest PCL trunk!

@SiddhantNadkarni
Copy link

Hey I couldn't get this working. Can we please have some good examples of the color jet features to point clouds?

@VictorLamoine
Copy link
Contributor

#1581 (comment)

@SiddhantNadkarni
Copy link

Hi Victor, thanks for replying. But I had already tried the code and it isn't working. Have you tried it out?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants