PCL obtains pcd point cloud with intensity information

1, Foreword

1. Overview

   pcl::PointXYZI in PCL is a data structure used to store xyz coordinates and intensity information. When CloudCompare is used to convert the point cloud in las format into pcd format, and then PCL is used to read the point cloud in pcd format, the intensity information can not be obtained (the intensity information can be read by open3d and matlab). The specific reason is not deeply studied at present.

The 3D laser scanner obtains the xyz and intensity information of the scanning target, so the most original las point cloud obtained by the scanner must contain xyz coordinates and intensity information. You have to say that your las point cloud has no strength, so I can't help it.

  many netizens are using it PCL bilateral filtering At the time of, they all privately believe how I use the code to obtain the point cloud with intensity information. This code implementation was written long ago and published on September 23, 2020 PCL point cloud format conversion There is the code of las2pcd in this paper; Published on October 17, 2020 Visual studio 2019 configuring LASlib and LAS format parsing In this paper, there is the conversion between laslib and pcl::PointXYZRGB in PCL; Published on May 15, 2021 PCL point clouds render colors by intensity , the intensity information is directly read from the las point cloud.
  this paper makes a simple summary of the methods used at present.

2. Get the real coordinates of point cloud from las

   there are two ways to obtain the real coordinates of the point cloud from the las point cloud:
Method 1: calculate and obtain [4] according to the calculation formula:
{ X c o o r d i n a t e = ( X r e c o r d ) × X s c a l e + X o f f s e t , Y c o o r d i n a t e = ( Y r e c o r d ) × Y s c a l e + Y o f f s e t , Z c o o r d i n a t e = ( Z r e c o r d ) × Z s c a l e + Z o f f s e t , \begin{cases} X_{coordinate}=(X_{record})\times X_{scale}+X_{offset},\\ Y_{coordinate}=(Y_{record})\times Y_{scale}+Y_{offset},\\ Z_{coordinate}=(Z_{record})\times Z_{scale}+Z_{offset},\\ \end{cases} ⎩⎪⎨⎪⎧​Xcoordinate​=(Xrecord​)×Xscale​+Xoffset​,Ycoordinate​=(Yrecord​)×Yscale​+Yoffset​,Zcoordinate​=(Zrecord​)×Zscale​+Zoffset​,​
   where, X r e c o r d X_{record} Xrecord​, Y r e c o r d Y_{record} Yrecord​, Z r e c o r d Z_{record} Zrecord is the recorded value in Li Dar point cloud data.
The corresponding implementation code is:

// Calculate the real coordinate information according to the formula
        cloud->points[i].x = lasreader->point.get_X() * xScale + xOffset;      // Get X coordinate
        cloud->points[i].y = lasreader->point.get_Y() * yScale + yOffset;      // Get Y coordinate
        cloud->points[i].z = lasreader->point.get_Z() * zScale + zOffset;      // Get Z coordinate
        cloud->points[i].intensity = lasreader->point.get_intensity();// Get reflection intensity
  • get_X(): in the formula X r e c o r d X_{record} Xrecord, others, and so on.

Method 2: obtain directly:

        cloud->points[i].x = lasreader->point.get_x();      // Get point cloud x real coordinates
        cloud->points[i].y = lasreader->point.get_y();      // Get point cloud y real coordinates
        cloud->points[i].z = lasreader->point.get_z();      // Get point cloud z real coordinates
        cloud->points[i].intensity = lasreader->point.get_intensity();// Get reflection intensity
  • get_x(): the obtained is the real coordinates of the point cloud.

For las point clouds with large coordinate values in CloudCompare, the offset will be subtracted for coordinate conversion, which is the function realized by this operation in the following figure:


For this operation, a simple implementation code is also written:

// Corresponds to the operation of subtracting offset in CloudCompare
        cloud->points[i].x = lasreader->point.get_x() - xOffset;      // Get X coordinate
        cloud->points[i].y = lasreader->point.get_y() - yOffset;      // Get Y coordinate
        cloud->points[i].z = lasreader->point.get_z() - zOffset;      // Get Z coordinate
        cloud->points[i].intensity = lasreader->point.get_intensity();// Get reflection intensity

To sum up, this paper gives three codes to obtain pcd point cloud with intensity from las point cloud

2, Code implementation

1. Get real coordinates directly

#include <iostream>
#include <lasreader. HPP > / / I have been encapsulated in the PCL library, so angle brackets are used
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>

using namespace std;

int main(int argc, char* argv[])
{
    LASreadOpener lasreadopener;                  // Open lasreader
    
    lasreadopener.set_file_name("data//3. Early las "); / / path of point cloud to be loaded
    LASreader* lasreader = lasreadopener.open(false); // The first parameter is whether to read only the information in the las header file
    if (lasreader == 0)
    {
        fprintf(stderr, "ERROR: could not open lasreader\n");

    }

    int pointAmount = lasreader->npoints; // Number of las midpoint

    pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>());
    cloud->width = pointAmount;
    cloud->height = 1;
    cloud->resize(lasreader->npoints);
    cloud->is_dense = false;

    size_t i = 0;
    while (lasreader->read_point() && i < pointAmount)
    {
        
        cloud->points[i].x = lasreader->point.get_x();      // Get point cloud x real coordinates
        cloud->points[i].y = lasreader->point.get_y();      // Get point cloud y real coordinates
        cloud->points[i].z = lasreader->point.get_z();      // Get point cloud z real coordinates
        cloud->points[i].intensity = lasreader->point.get_intensity();// Get reflection intensity

        ++i;
    }
    pcl::io::savePCDFileBinary("las2PointXYZI.pcd", *cloud);  // Save as pcd with intensity information
    printf("PointXYZI Type pcd Point cloud acquisition completed!!!");
    lasreader->close(); // Close lasreader
    delete lasreader;
    lasreader = nullptr;

    return 0;
}

2. Calculate the formula to obtain the real coordinates

#include <iostream>
#include <lasreader.hpp>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>

using namespace std;

int main(int argc, char* argv[])
{
    LASreadOpener lasreadopener;
    // open lasreader
    lasreadopener.set_file_name("data//3. Early las");
    LASreader* lasreader = lasreadopener.open(false);
    if (lasreader == 0)
    {
        fprintf(stderr, "ERROR: could not open lasreader\n");

    }

    double xOffset = lasreader->header.x_offset;                // Offset in X direction
    double yOffset = lasreader->header.y_offset;                // Offset in Y direction
    double zOffset = lasreader->header.z_offset;                // Offset in Z direction
    F64 xScale = lasreader->header.x_scale_factor;           // Scale factor in X direction
    F64 yScale = lasreader->header.y_scale_factor;           // Scale factor in Y direction
    F64 zScale = lasreader->header.z_scale_factor;           // Scale factor in Z direction
    

    cout << "X The offset of the direction is:" << xOffset << "Y The offset of the direction is:" << yOffset << "Z The offset of the direction is:" << zOffset << endl;
    cout << "X The scale factor of the direction is:" << xScale << "Y The scale factor of the direction is:" << yScale << "Z The scale factor of the direction is:" << zScale << endl;
   
    int pointAmount = lasreader->npoints;

    pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>());
    cloud->width = pointAmount;
    cloud->height = 1;
    cloud->resize(lasreader->npoints);
    cloud->is_dense = false;
    size_t i = 0;
    while (lasreader->read_point() && i < pointAmount)
    {
        // Calculate the real coordinate information according to the formula
        cloud->points[i].x = lasreader->point.get_X() * xScale + xOffset;      // Get X coordinate
        cloud->points[i].y = lasreader->point.get_Y() * yScale + yOffset;      // Get Y coordinate
        cloud->points[i].z = lasreader->point.get_Z() * zScale + zOffset;      // Get Z coordinate
        cloud->points[i].intensity = lasreader->point.get_intensity();// Get reflection intensity

        ++i;
    }
    pcl::io::savePCDFileBinary("las2PointXYZI.pcd", *cloud);  // Save as pcd with intensity information
    printf("PointXYZI Type pcd Point cloud acquisition completed!!!");

    lasreader->close(); // Close lasreader
    delete lasreader;
    lasreader = nullptr;

    return 0;
}

3. Subtract offset value from CC

It should be noted here that when the offset value is not provided in the las header file or the provided offset value is very small, CloudCompare software is more intelligent and will automatically calculate an appropriate offset, while the code only reads the offset value from the las header file.

#include <iostream>
#include <lasreader.hpp>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>

using namespace std;

int main(int argc, char* argv[])
{
    LASreadOpener lasreadopener;
    // open lasreader
    lasreadopener.set_file_name("data//3. Early las");
    LASreader* lasreader = lasreadopener.open(false);
    if (lasreader == 0)
    {
        fprintf(stderr, "ERROR: could not open lasreader\n");

    }

    double xOffset = lasreader->header.x_offset;                // Offset in X direction
    double yOffset = lasreader->header.y_offset;                // Offset in Y direction
    double zOffset = lasreader->header.z_offset;                // Offset in Z direction
    
    cout << "X The offset of the direction is:" << xOffset << "Y The offset of the direction is:" << yOffset << "Z The offset of the direction is:" << zOffset << endl;
   
    int pointAmount = lasreader->npoints;

    pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>());
    cloud->width = pointAmount;
    cloud->height = 1;
    cloud->resize(lasreader->npoints);
    cloud->is_dense = false;
    size_t i = 0;
    while (lasreader->read_point() && i < pointAmount)
    {
        // Corresponds to the operation of subtracting offset in CloudCompare
        cloud->points[i].x = lasreader->point.get_x() - xOffset;      // Get X coordinate
        cloud->points[i].y = lasreader->point.get_y() - yOffset;      // Get Y coordinate
        cloud->points[i].z = lasreader->point.get_z() - zOffset;      // Get Z coordinate
        cloud->points[i].intensity = lasreader->point.get_intensity();// Get reflection intensity

        ++i;
    }
    pcl::io::savePCDFileBinary("las2PointXYZI.pcd", *cloud);  // Save as pcd with intensity information
    printf("PointXYZI Type pcd Point cloud acquisition completed!!!");

    lasreader->close(); // Close lasreader
    delete lasreader;
    lasreader = nullptr;

    return 0;
}

3, Result display

The following is the display result of directly reading the pcd format point cloud converted by the above code

4, Get pcd point cloud with intensity from txt

The efficiency of this method is very low. The implementation method and code are also given here
First, use CloudCompare software to save las point cloud in txt format


Then convert with the following code:

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/time.h>

using namespace std;

//Read point cloud data
bool readTxtFile(const string& fileName, const char tag, const pcl::PointCloud<pcl::PointXYZI>::Ptr pointCloud)
{
	cout << "reading file start..... " << endl;
	ifstream fin(fileName);
	string linestr;
	while (getline(fin, linestr))
	{
		vector<string> strvec;
		string s;
		stringstream ss(linestr);
		while (getline(ss, s, tag))
		{
			strvec.push_back(s);
		}
		pcl::PointXYZI p;
		p.x = stod(strvec[0]);
		p.y = stod(strvec[1]);
		p.z = stod(strvec[2]);
		p.intensity = stoi(strvec[3]);
		pointCloud->points.push_back(p);
	}
	cout << "reading file finished! " << endl;
	cout << "There are " << pointCloud->points.size() << " points!" << endl;
	return true;
}

int main()
{
	string filename = "Cloud.txt";
	pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>());
	pcl::StopWatch time;
	readTxtFile(filename, ' ', cloud);
	cout << "Running time:" << time.getTime() << "millisecond" << endl;
	pcl::io::savePCDFileBinary("txt2PointXYZI.pcd", *cloud);  // Save as pcd with intensity information
	printf("PointXYZI Type pcd Point cloud acquisition completed!!!");


	return (0);
}

1482821 points in debug mode, and the code running time is 58397.1 milliseconds

reading file start.....
reading file finished!
There are 1482821 points!
Running time:58397.1 millisecond
PointXYZI Type pcd Point cloud acquisition completed!!!

In debug mode, 1482821 points are directly converted with las, and the code running time is 422.23 milliseconds

Running time:422.23 millisecond
PointXYZI Type pcd Point cloud acquisition completed!!!

5, Related links

[1] PCL bilateral filtering
[2] LASlib read / write point cloud
[3] PCL point cloud format conversion
[4] Visual studio 2019 configuring LASlib and LAS format parsing
[5] PCL point clouds render colors by intensity
[6] PCL - KITTI data set bin file to pcd and visualization

Keywords: Algorithm AI Computer Vision 3d

Added by Sweeney on Sat, 08 Jan 2022 04:22:45 +0200