pcl icon indicating copy to clipboard operation
pcl copied to clipboard

[visualization] PCLVisualizer::addCorrespondences/updateCorrespondences does not show all correspondences

Open themightyoarfish opened this issue 2 years ago • 9 comments
trafficstars

Describe the bug

I use Registration::registerVisualizationCallback() to show correspondences. The code employs PCLVisualizer::addCorrespondences(). This does not lead to all correspondences getting shown. If instead I iterate over all correspondences manually and addLine() for each, all are shown as expected. Somewhere inside PCLVisualizer, items get lost.

Expected behavior

All correspondences passed to addCorrespondences() function should be shown.

Current Behavior

Not all correspondences passed to addCorrespondences() function are shown.

To Reproduce

mwe.cpp

#include <pcl/io/pcd_io.h>
#include <pcl/registration/icp.h>

#include <pcl/visualization/pcl_visualizer.h>

using namespace std;
using namespace pcl;
using namespace pcl::visualization;

using PointT = PointXYZ;
using CloudT = PointCloud<PointT>;
using namespace Eigen;

struct RegistrationVisualizer {

  pcl::visualization::PCLVisualizer::Ptr optimization_viewer;

  RegistrationVisualizer();

  void visualize_registration(pcl::Registration<PointT, PointT> &reg);
};

int main(int argc, char *argv[]) {
  Matrix4f transformation;
  transformation << 1, 0, 0, 6.7, 0, 1, 0, 12.3, 0, 0, 1, 0.7, 0, 0, 0, 1;

  CloudT::Ptr source{new CloudT};
  CloudT::Ptr target{new CloudT};
  io::loadPCDFile("../scene_filtered.pcd", *target);
  io::loadPCDFile("../template.pcd", *source);

  IterativeClosestPoint<PointT, PointT> icp;
  icp.setInputSource(source);
  icp.setInputTarget(target);
  icp.setMaxCorrespondenceDistance(0.1);
  RegistrationVisualizer regvis;
  regvis.visualize_registration(icp);

  icp.align(*source, transformation);
  return 0;
}

RegistrationVisualizer::RegistrationVisualizer() {
  optimization_viewer = pcl::make_shared<pcl::visualization::PCLVisualizer>();
  optimization_viewer->setWindowName("Correspondences");
}

void RegistrationVisualizer::visualize_registration(
    pcl::Registration<PointT, PointT> &reg) {
  using namespace pcl;
  using namespace pcl::visualization;

  std::function<
      pcl::Registration<PointT, PointT>::UpdateVisualizerCallbackSignature>
      callback([this](const CloudT &c1, const pcl::Indices &idxs1,
                      const CloudT &c2, const pcl::Indices &idxs2) {
        if (!idxs1.size() || !idxs2.size()) {
          return;
        }

        // turn idxs into one correspondence vector
        Correspondences correspondences;
        for (size_t i = 0; i < idxs1.size(); ++i) {
          correspondences.push_back(Correspondence(idxs1[i], idxs2[i], 1));
        }

        // viewer needs ptrs, not values (expensiveish)
        const CloudT::Ptr c1_correspondences = c1.makeShared();
        const CloudT::Ptr c2_correspondences = c2.makeShared();

        if (!this->optimization_viewer->updatePointCloud<PointT>(
                c1_correspondences, "c1")) {
          this->optimization_viewer->addPointCloud<PointT>(c1_correspondences,
                                                           "c1");
          this->optimization_viewer->setPointCloudRenderingProperties(
              PCL_VISUALIZER_COLOR, 0, 1, 1, "c1");
          this->optimization_viewer->setPointCloudRenderingProperties(
              PCL_VISUALIZER_POINT_SIZE, 3, "c1");
        }
        if (!this->optimization_viewer->updateText("Source", 10, 10)) {
          this->optimization_viewer->addText("Source", 10, 10, 20, 0, 1, 1);
        }
        if (!this->optimization_viewer->updatePointCloud<PointT>(
                c2_correspondences, "c2")) {
          this->optimization_viewer->addPointCloud<PointT>(c2_correspondences,
                                                           "c2");
          this->optimization_viewer->setPointCloudRenderingProperties(
              PCL_VISUALIZER_COLOR, 1, 1, 0, "c2");
          this->optimization_viewer->setPointCloudRenderingProperties(
              PCL_VISUALIZER_POINT_SIZE, 3, "c2");
        }
        if (!this->optimization_viewer->updateText("Target", 10, 40)) {
          this->optimization_viewer->addText("Target", 10, 40, 20, 1, 1, 0);
        }

        // works as expected
        /* int c = 0; */
        /* for (const auto& corr : correspondences) { */
        /*   const auto p1     = c1_correspondences->points[corr.index_query]; */
        /*   const auto p2     = c2_correspondences->points[corr.index_match]; */
        /*   const string name = "line" + to_string(c); */
        /*   this->optimization_viewer->removeShape(name); */
        /*   this->optimization_viewer->addLine(p1, p2, 1, 0, 0, name); */
        /*   c++; */
        /* } */

        // many lines missing
        if (!this->optimization_viewer->updateCorrespondences<PointT>(
                c1_correspondences, c2_correspondences, correspondences)) {
          this->optimization_viewer->addCorrespondences<PointT>(
              c1_correspondences, c2_correspondences, correspondences,
              "correspondences");
        }
        this->optimization_viewer->setShapeRenderingProperties(
            PCL_VISUALIZER_LINE_WIDTH, 5, "correspondences");
        this->optimization_viewer->spin();
      });
  reg.registerVisualizationCallback(callback);
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.19.8)
set(CMAKE_CXX_STANDARD 20)
find_package(PCL REQUIRED)
add_executable(mwe mwe.cpp)
target_link_libraries(mwe ${PCL_LIBRARIES})
target_include_directories(mwe PRIVATE ${PCL_INCLUDE_DIRS})

pcds:

pcds.zip

First screenshot is using updateCorrespondences(). Notice how on the right there are no correspondences.

Screenshot 2023-06-18 at 20 14 55

Second screenshot I add them by hand with addLine(). Many correspondences on the right.

Screenshot 2023-06-18 at 20 15 18

Your Environment (please complete the following information):

  • OS: macos 12.6.5
  • Compiler: Apple clang version 14.0.0 (clang-1400.0.29.202) (arm)
  • PCL Version 1.13 (4d8f60706c5d97c4a5b3b3da65f107cc7716ce1e)

I'm at a loss here. I don't know VTK, but the code in addCorrespondences() does not look wrong. I could verify that in https://github.com/PointCloudLibrary/pcl/blob/master/visualization/include/pcl/visualization/impl/pcl_visualizer.hpp#L1259, the full number of found correspondences is iterated, but somehow not everything shows up. This led me on a merry chase as I had first assumed the correspondence estimation to somehow fail, but it seems to be just the visualization.

themightyoarfish avatar Jun 18 '23 17:06 themightyoarfish

Seems to be working fine on windows, with vtk 9.2 - and recently PCL master.

image

larshg avatar Jun 19 '23 05:06 larshg

Could be a glitch in VTK? since the code in PCL looks correct and seems to work correctly as well - however it fails to visualize on your system. What VTK version do you use?

larshg avatar Jun 19 '23 05:06 larshg

VTK seems to be 9.1.0, perhaps I can try a different version here.

themightyoarfish avatar Jun 19 '23 06:06 themightyoarfish

I built PCL and this sample code against VTK 9.2.6 (current release) and it exhibits the same behavior, so seems to be a macos problem.

themightyoarfish avatar Jun 19 '23 09:06 themightyoarfish

I (Ubuntu 23.04, VTK 9.1.0) see the same as Lars. So yes, possibly only a problem on macos. @themightyoarfish Can you maybe try to shuffle or reverse correspondences, to check whether it then displays only lines on the right but not in the center?

mvieth avatar Jul 01 '23 14:07 mvieth

If I shuffle them, i get some lines everywhere, just not all.

without shuffle:

Screenshot 2023-07-02 at 09 59 33

with shuffle: Screenshot 2023-07-02 at 10 01 26

themightyoarfish avatar Jul 02 '23 08:07 themightyoarfish

It seems that the points on the right just happen to come later in the vector, and VTK here manages only some percentage of the entries … if I limit the display to the last half or last third or so, I see an increasing number of lines on the right being drawn.

themightyoarfish avatar Jul 02 '23 08:07 themightyoarfish

@themightyoarfish I rewrote addCorrespondences as a VTK-only test program: vtktest.txt (rename to vtktest.cpp) CMakeLists.txt

It should display a whole circle (for me it does). You could test what you see, and also what happens when you change n_lines. You could also use it to estimate how many lines are displayed for you (how much of the circle is visible).

mvieth avatar Jul 28 '23 12:07 mvieth

I tried different orders of magnitude, but I always see the full circle. So the same issue doesn't seem to appear here.

themightyoarfish avatar Jul 28 '23 13:07 themightyoarfish