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