PointCloudLibrary / PointCloudLibrary/pcl

Possible Bug in PCL_visualizer when adding model object.

Open
#1,781 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: stale
Dominant language
C++
Stars
11.1k
Forks
4.7k
Avg merge
4d 10h
Merged PRs (30d)
6

Description

I can say that there is a bug in PCL_visualizer for the pcl version 1.7.2 and version 1.8.0.
I have tested the code on three different version of pcl 1.6 - 1.8 on different machines.

windows 7 32bit All-in-one pcl installer - v1.6
ubuntu 14.04 LTS repo install - v1.7.2
Windows 10 64bit source compiled - v1.8

the issue is related to co-ordinate shown in the visualizer which seems to be not correct.

THE CODE:

#include <vtkIdList.h>
#include <vtkPoints.h>
#include <vtkOBBTree.h>
#include <vtkBoundingBox.h>

#include <iostream>

#include <pcl/ModelCoefficients.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/pcd_io.h>
#include <pcl/common/centroid.h>
#include <pcl/common/common.h>
#include <pcl/common/transforms.h>
#include <pcl/filters/project_inliers.h>

int 
main() 
{ 
        pcl::ModelCoefficients::Ptr cylinder_Coeff (new pcl::ModelCoefficients); 

        for(int i = 0; i < 7; i++) 
        { 
        cylinder_Coeff->values.push_back(i); 
        } 
        std::string filename; 
        double corner[3], max[3], min[3], mid[3], size[3]; 
        
        vtkSmartPointer<vtkOBBTree> OBB = vtkSmartPointer<vtkOBBTree>::New(); 
        pcl::visualization::PCLVisualizer *visu; 

        std::cout << "Enter the filename\n"; 
        std::cin >> filename; 
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); 
        pcl::io::loadPCDFile<pcl::PointXYZ> (filename, *cloud); 
        
        
        ///pointCloud to VtkIDlist 
        vtkIdType nr_points = cloud->points.size(); 
        vtkPoints* points = vtkPoints::New(); 
        points->SetDataTypeToFloat(); 
        points->SetNumberOfPoints(nr_points); 
        
        /*vtkBoundingBox Bounding; 
        for (int i = 0; i < cloud->points.size(); i++) 
        { 
        Bounding.AddPoint(cloud->points[i].x, cloud->points[i].y, cloud->points[i].z); 
        } 
        double bounds[6]; 
        Bounding.GetBounds(bounds);*/ 

        if (cloud->is_dense) 
        { 
                for (vtkIdType i = 0; i < nr_points; ++i) { 
                        float point[3] = {cloud->points[i].x, cloud->points[i].y, cloud->points[i].z}; 
                        points->SetPoint(i, point); 
                } 
        } 
        else 
        { 
                vtkIdType j = 0;    // true point index 
                for (vtkIdType i = 0; i < nr_points; ++i) 
                { 
                // Check if the point is invalid 
                        if (!pcl_isfinite (cloud->points[i].x) || 
                                !pcl_isfinite (cloud->points[i].y) || 
                                !pcl_isfinite (cloud->points[i].z)) 
                        continue; 

                        float point[3] = {cloud->points[i].x, cloud->points[i].y, cloud->points[i].z}; 
                        points->SetPoint(j, point); 
                        j++; 
                } 
                nr_points = j; 
                points->SetNumberOfPoints(nr_points); 
        } 
        
        OBB->ComputeOBB(points, corner, max, mid, min, size); 
        
        //below code is required to get correct length of the vectors 
        Eigen::Vector4f pcaCentroid,pcaCentroidTransformed; 
        pcl::compute3DCentroid(*cloud, pcaCentroid); 
                
        Eigen::Matrix3f covariance; 
        computeCovarianceMatrixNormalized(*cloud, pcaCentroid, covariance); 
        Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors); 
        
        Eigen::Matrix3f eigenVectorsPCA = eigen_solver.eigenvectors(); 
        eigenVectorsPCA.col(2) = eigenVectorsPCA.col(0).cross(eigenVectorsPCA.col(1)); 
        
        Eigen::Matrix4f projectionTransform(Eigen::Matrix4f::Identity()); 
        projectionTransform.block<3,3>(0,0) = eigenVectorsPCA.transpose(); 
        projectionTransform.block<3,1>(0,3) = -1.f * (projectionTransform.block<3,3>(0,0) * pcaCentroid.head<3>()); 

        
        pcl::PointCloud<pcl::PointXYZ>::Ptr cloudPointsProjected (new pcl::PointCloud<pcl::PointXYZ>); 
        pcl::transformPointCloud(*cloud, *cloudPointsProjected, projectionTransform); 
        pcl::compute3DCentroid(*cloudPointsProjected, pcaCentroidTransformed); 


        pcl::PointXYZ minPoint, maxPoint, lineP1, lineP2; 
        pcl::getMinMax3D(*cloudPointsProjected, minPoint, maxPoint); 
        const Eigen::Vector3f meanDiagonal = 0.5f *(maxPoint.getVector3fMap() + minPoint.getVector3fMap()); 

        const Eigen::Quaternionf bboxQuaternion(eigenVectorsPCA); //Quaternions are a way to do rotations https://www.youtube.com/watch?v=mHVwd8gYLnI
        const Eigen::Vector3f bboxTransform = eigenVectorsPCA * meanDiagonal + pcaCentroid.head<3>(); 
                
        double height, width, depth, a, b, c, radius; 
        a = maxPoint.y - minPoint.y; 
        b = maxPoint.x - minPoint.x; 
        c = maxPoint.z - minPoint.z; 

        if(a > b && a > c){ 
                height = a; 
                if (b > c) 
                { 
                        cylinder_Coeff->values[6] = b/2; 
                } 
                else 
                { 
                        cylinder_Coeff->values[6] = c/2; 
                } 

        } 
        else if (b > a && b > c){ 
                height = b; 
                if(a > c) 
                { 
                        cylinder_Coeff->values[6] = a/2; 
                } 
                else 
                { 
                        cylinder_Coeff->values[6] = c/2; 
                } 
        } 
        else if (c > a && c >b){ 
                height = c; 
                if(a > b) 
                { 
                        cylinder_Coeff->values[6] = a/2; 
                } 
                else 
                { 
                        cylinder_Coeff->values[6] = b/2; 
                } 
        } 

        pcl::ModelCoefficients::Ptr sphere_Coeff (new pcl::ModelCoefficients); 
        //this will make sphere at the origin 
        sphere_Coeff->values.push_back(0); 
        sphere_Coeff->values.push_back(0); 
        sphere_Coeff->values.push_back(0); 
        sphere_Coeff->values.push_back(2); 

        //Normalizing the vectors 
        double n_max[3], n_min[3], n_mid[3], l_max, l_min, l_mid; 
        l_max = sqrt( pow(max[0],2) + pow(max[1],2) + pow(max[2],2)); 
        l_min = sqrt( pow(min[0],2) + pow(min[1],2) + pow(min[2],2)); 
        l_mid = sqrt( pow(mid[0],2) + pow(mid[1],2) + pow(mid[2],2)); 

        n_max[0] = max[0]/l_max; 
        n_max[1] = max[1]/l_max; 
        n_max[2] = max[2]/l_max; 

        n_min[0] = min[0]/l_min; 
        n_min[1] = min[1]/l_min; 
        n_min[2] = min[2]/l_min; 

        n_mid[0] = mid[0]/l_mid; 
        n_mid[1] = mid[1]/l_mid; 
        n_mid[2] = mid[2]/l_mid; 

        pcl::ModelCoefficients::Ptr line_Coeff (new pcl::ModelCoefficients); 
        line_Coeff->values.resize(6); 
        line_Coeff->values[0] = pcaCentroid(0) - ((height/2) * n_max[0]) + (cylinder_Coeff->values[6] * n_mid[0]); 
        line_Coeff->values[1] = pcaCentroid(1) - ((height/2) * n_max[1]) + (cylinder_Coeff->values[6] * n_mid[1]); 
        line_Coeff->values[2] = pcaCentroid(2) - ((height/2) * n_max[2]) + (cylinder_Coeff->values[6] * n_mid[2]); 
        line_Coeff->values[3] = ((height/2) * n_max[0]); 
        line_Coeff->values[4] = ((height/2) * n_max[1]); 
        line_Coeff->values[5] = ((height/2) * n_max[2]); 

        lineP1.x = pcaCentroid(0) - ((height/2) * n_max[0]);// + (cylinder_Coeff->values[6] * n_min[0]); 
        lineP1.y = pcaCentroid(1) - ((height/2) * n_max[1]);// + (cylinder_Coeff->values[6] * n_min[1]); 
        lineP1.z = pcaCentroid(2) - ((height/2) * n_max[2]);// + (cylinder_Coeff->values[6] * n_min[2]); 
        lineP2.x = pcaCentroid(0) + ((height/2) * n_max[0]);// + (cylinder_Coeff->values[6] * n_min[0]); 
        lineP2.y = pcaCentroid(1) + ((height/2) * n_max[1]);//+ (cylinder_Coeff->values[6] * n_min[1]); 
        lineP2.z = pcaCentroid(2) + ((height/2) * n_max[2]);// + (cylinder_Coeff->values[6] * n_min[2]); 

        cylinder_Coeff->values[0] = pcaCentroid(0) - ((height/2) * n_max[0]); 
        cylinder_Coeff->values[1] = pcaCentroid(1) - ((height/2) * n_max[1]); 
        cylinder_Coeff->values[2] = pcaCentroid(2) - ((height/2) * n_max[2]); 
        cylinder_Coeff->values[3] = ((height) * n_max[0]); 
        cylinder_Coeff->values[4] = ((height) * n_max[1]); 
        cylinder_Coeff->values[5] = ((height) * n_max[2]); 

        for(int i = 0; i < 3; i++) 
        { 
                std::cout << corner[i] << "   " << max[i] << "   " << mid[i] << "   " << min[i] << "   " << size[i] << std::endl; 
        } 
        

        visu = new pcl::visualization::PCLVisualizer ("PlyViewer"); 
        int vp; 

        visu->addLine(lineP1, lineP2, "line"); 
        visu->addSphere(*sphere_Coeff, "sph"); 
        visu->addCylinder(*cylinder_Coeff, "cyl"); 
        visu->addCube(bboxTransform, bboxQuaternion, maxPoint.x - minPoint.x, maxPoint.y - minPoint.y, maxPoint.z - minPoint.z, "bbox"); 
        visu->addCoordinateSystem(0.5); 
        visu->addPointCloud(cloud, "ogCloud"); 
        visu->updatePointCloud(cloud, "ogCloud"); 

        while (!visu->wasStopped ()) 
        { 
                visu->spinOnce (100); 
                boost::this_thread::sleep (boost::posix_time::microseconds (100000)); 
        } 
        return 0; 
} 

results_with_pcl1 8
result_using_pcl1 6
result_with_pcl1 7 2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the supplied program with the listed PCL 1.6, 1.7.2, and 1.8 environments, focusing on PCLVisualizer calls such as addLine, addCylinder, addCube, and addCoordinateSystem. Compare the displayed coordinates with the computed point-cloud and bounding-box values. Done means identifying and documenting a reproducible visualization defect with a consistent result across supported versions.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
computer-graphics, computer-vision
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.