读取 .las 文件,用 PCL 处理和显示
Posted
技术标签:
【中文标题】读取 .las 文件,用 PCL 处理和显示【英文标题】:Reading .las file, processing and displaying it with PCL 【发布时间】:2021-05-08 03:07:30 【问题描述】:我使用 libLAS 库来读取 .las file 的浊点。然后我将点存储在 PCL 点云变量中,以便使用点云库处理和显示点云。
这是我使用的代码:
class PointCloud
public:
//PointCloud(const std::string& path);
uint32_t getVertsCount();
float4* getVertsData();
template<typename PointT>
typename pcl::PointCloud<PointT>::Ptr read(const std::string& path);//void read(const std::string &path);
template<typename PointT>
typename pcl::PointCloud<PointT>::Ptr PointCloud::read(const string& path)
typename pcl::PointCloud<PointT>::Ptr lasCloud(new pcl::PointCloud<PointT>);
std::ifstream ifs;
ifs.open(path, std::ios::in | std::ios::binary);
//std::ifstream inf(path, std::ios::in | std::ios::binary);
liblas::ReaderFactory f;
liblas::Reader reader = f.CreateWithStream(ifs);
liblas::Header const& header = reader.GetHeader();
std::cout << "Compressed: " << (header.Compressed() == true) ? "true" : "false";
std::cout << "Signature: " << header.GetFileSignature() << '\n';
std::cout << "Points count: " << header.GetPointRecordsCount() << '\n';
while (reader.ReadNextPoint())
liblas::Point const& p = reader.GetPoint();
PointT cloudPoint;
cloudPoint.x = float(p.GetX()) * 0.001 + 590284.000; // (double)(x * scaleX) + offsetX;
cloudPoint.y = float(p.GetY()) * 0.001 + 4339456.000; // (double)(y * scaleY) + offsetY;
cloudPoint.z = float(p.GetZ()) * 0.001 + 157.000; // (double)(z * scaleZ) + offsetZ;
std::cout << p.GetX() << ", " << p.GetY() << ", " << p.GetZ() << "\n";
//cloudPoint.intensity = p.GetIntensity(); // (double)(intensity) / 65536.0;
lasCloud->points.push_back(cloudPoint);
if (!ifs.good())
throw runtime_error("Reading went wrong!");
lasCloud->width = lasCloud->points.size();
lasCloud->height = 1;
lasCloud->is_dense = true;
std::cout << "Cloud size = " << lasCloud->points.size() << endl;
return lasCloud;
int main (int argc, char** argv)
std::cout << "starting enviroment" << std::endl;
pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
CameraAngle setAngle = FPS; //XY, FPS, Side, TopDown
initCamera(setAngle, viewer);
pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloudI; //
inputCloudI = pcd.read<pcl::PointXYZ>("C:/Users/hedey/OneDrive/Documents/Research_papers/STDF/10_4231_MFQF-Q141/I-65/LiDAR/RoadSurface/NB/20180524_I65_NB_RoadSurface_1_50.5.las");
std::cout << "Cloud size = " << inputCloudI->points.size() << endl;
renderPointCloud(viewer, inputCloudI, "lasCloud");
while (!viewer->wasStopped())
viewer->spinOnce();
但是,使用 PCL 查看器显示的云看起来像一个点。我注意到,当我打印出使用 libLAS 读取的坐标时,x & y 坐标没有十进制值,这与 las 文件中存储的实际坐标相比是不准确的。我从命令提示符使用 las2txt 获得了实际的点坐标。 This is the txt file 包含实际坐标。这是显示 cout 结果的图像:
另外,这就是我使用 CloudCompare 打开点云时的样子。当我将它读入 PCL 点云变量并使用 PCL 查看器显示结果时,我期待得到相同的显示,因为我需要进行进一步处理才能进行传感器融合(相机和激光雷达)。
【问题讨论】:
【参考方案1】:std::cout
的默认精度为 6 位十进制数字。请添加类似
std::cout.precision(12);
while
循环之前。
此外,将p.GetX()
等转换为float
是没有意义的:如果将其乘以0.001
,则 operator* 参数的左侧自然会至少提升为double
。然而,float
只有大约 7 位的精度,所以对于存储在双精度中的 9 位整数(是的!),这种截断是灾难性的。
还有另一个(小)错误,正确的行显示
std::cout << "Compressed: " << ((header.Compressed() == true) ? "true\n" : "false\n");
请注意条件表达式(和\n
)周围的 () 大括号。请使用标准编译器选项来警告此类简单问题。
另请阅读https://***.com/help/minimal-reproducible-example
【讨论】:
非常感谢。我一直在谷歌搜索和研究这个主题。现在,我的理解是读取的坐标已经应用了比例和偏移量,所以我不必应用它们。我只需要按原样使用读取的坐标。另外,我找到了渲染点云的解决方案。只需按“R”键,可视化器就会调整到坐标。我现在唯一担心的是例如 p.GetX() 是双精度数。当我将它分配给浮点数的 cloudPoint.x 时,精度会受到影响。例如,p.GetX()=600209.172 但是 cloudPoint.x=600209.1875。如何解决? 你不能。如果您仅将 PCL 用于可视化,则在将数据传输到 PCL 之前,更改坐标系以使值的大小变得相当小。例如,移动它,使云的质心位于 (0.0.0)。 我将使用 PCL 不仅用于可视化,还将用于其他点云处理(如分割、聚类等),并在此基础上将传感器与相机图像融合。我的理解是 PCL 坐标以米为单位,十进制值增加了厘米精度。那么,这会导致测量精度降低(以厘米为单位)吗?我是这个领域的新手,所以我还在探索中。 如果所有值都以相同的数字开头,例如 678,那么您可以放心地忽略它们。实际上,PCL 是干什么用的?我不知道。分割、聚类和图像有什么关系,比如电脑游戏中的场景?那么不仅可以,而且应该使用局部坐标系。 非常感谢。从坐标中删除相同的数字(以获得较小的坐标值)几乎解决了精度问题。我认为这就是所谓的坐标偏移。现在将 double 'p.GetX()' 分配给 float 'cloudPoint.x' 后,cloudPoint.x 的值为 9.17199993134,这使得小数部分非常接近 0.172。再次感谢先生。以上是关于读取 .las 文件,用 PCL 处理和显示的主要内容,如果未能解决你的问题,请参考以下文章
在python中使用liblas和laspy读取las文件的问题