在C++中打开LAS文件,输出看似不正确的值



我将在序言中说,我对C++非常陌生,如果我犯了任何严重的错误,请原谅我。

我正在尝试编写一个c++程序来输入las文件并输出每个点的坐标向量。我关注了这个youtube视频(https://www.youtube.com/watch?v=vdaWvEH2xNU)寻求帮助,我已经非常接近(我认为)获得正确的价值观。

当我在python中制作一个python来完成这一操作时,它会给我正确的ENU:坐标

import laspy
import numpy as np
las = laspy.read('ppk_cloud_1.las')
point_data = np.stack([las.x, las.y, las.z], axis=0).transpose((1, 0))
print(point_data)
--outputs--
[[2.73720833e+05 4.33655312e+06 1.55323500e+02]
[2.73720833e+05 4.33655312e+06 1.55323500e+02]
[2.73720742e+05 4.33655314e+06 1.55200500e+02]
...

然而,我在c++中的程序输出这些值:

[0]:{x=273720.844 y=8631520.00 z=4295122.50 }
[1]:{x=273720.844 y=8631520.00 z=4295122.50 }
[2]:{x=273720.750 y=8631520.00 z=4295122.50 }
[3]:{x=273720.750 y=8631520.00 z=4295122.50 }
...
[27]:{x=273728.188 y=8631521.00 z=4295116.50 }
[28]:{x=273727.719 y=4336556.00 z=4295117.50 }
[29]:{x=273727.719 y=4336556.00 z=4295117.50 }
[30]:{x=273727.625 y=4336556.00 z=4295117.50 }

x值几乎在那里(不完全相同,但很接近),但其他两个值则不一样。y值开始时非常偏离,然后跳到接近正确的值(它在这些值之间跳了几次……真的很困惑)。z值是错误的。(数值应以米为单位)

我对一个可能的问题的看法:

(1) Endianess-可能cpp正在读取小端序的二进制文件(我在英特尔计算机上),而las文件是用大端序写的。(通过意识到头文件偏移量(header.x_off,y_off,z_off ~=273664.464336554.51161.24)正是我想要的,排除了这一点。

(2) 它读取的是偏移的实际点(而不是标头)——我仔细检查了header.point_data_offset值,我确信这是正确的。

(3) 在视频中,他没有使用(float)((point.x * header.x_scale) + header.x_off),而是使用(float)((point.x * header.x_scale) + header.x_off),但在文档中(https://www.asprs.org/a/society/committees/lidar/Downloads/ASPRS_LAS%201_2.pdf),第5页,上面写着";因此,要从点记录缩放给定的X,请取点记录X乘以X比例因子,然后加上X偏移量";。因此,我认为我的公式应该是正确的(但我认为这是我问题的根源)。

(4) 也许这些值是正确的,只是在不同的坐标系中?(似乎标题和点不太可能在不同的坐标系中)。

任何帮助都将不胜感激。谢谢!:)

参考这里是我的cpp文件:

#include <iostream>
#include <fstream>
#include <stdexcept>
#include <assert.h>
#include "point_cloud.h"

PointCloud::PointCloud(const std::string &path)
{
read(path);
}
void PointCloud::read(const std::string &path)
{
std::ifstream inf(path, std::ios::binary);
if (inf.is_open())
{
Header header;
inf.read((char *)&header, sizeof(header));
assert(header.vers_major == 1 && header.vers_minor == 2);
assert(header.header_size == sizeof(header));
assert(header.point_data_record_format == 1);
inf.seekg(header.point_data_offset);
for (uint32_t i = 0; i < header.n_points; i++)
{
PointFormat1 point;
inf.read((char*)&point, sizeof(PointFormat1));
assert(sizeof(point) == sizeof(PointFormat1));
xyzfloats r = 
{
(float)((point.x * header.x_scale) + header.x_off),
(float)((point.y * header.y_scale) + header.y_off),
(float)((point.z * header.z_scale) + header.z_off)
};
//std::cout << r.x << "," << r.y << "," << r.z << std::endl;

coordinates.push_back(r);
}
std::cout << "done." << std::endl;
}
else
{
throw std::runtime_error("Can't find file.");
}
}
uint32_t PointCloud::get_n_points()
{
return (uint32_t)coordinates.size();
}
xyzfloats *PointCloud::getcoordinates()
{
return coordinates.data();
}

这是我的头文件:

#pragma once
#include <vector>
#include <string>
//https://www.asprs.org/wp-content/uploads/2010/12/LAS_1_4_r13.pdf
struct xyzfloats
{
float x, y, z;
};

class PointCloud
{
public:
PointCloud(const std::string &path);
uint32_t get_n_points();
xyzfloats *getcoordinates();

private:
std::vector<xyzfloats> coordinates;
#pragma pack(push, 1)
struct Header
{
char     file_sig[4];
uint16_t file_source_id;
uint16_t global_encoding;
uint32_t guid_data_1;
uint16_t guid_data_2;
uint16_t guid_data_3;
uint8_t  guid_data_4[8];
uint8_t  vers_major, vers_minor;
char     sys_identifier[32];
char     generating_software[32];
uint16_t creation_day, creation_year;
uint16_t header_size;
uint32_t point_data_offset;
uint32_t n_var_length_records;
uint8_t  point_data_record_format;
uint16_t point_data_record_length;
uint32_t n_points;
uint32_t n_points_by_return[5];
double   x_scale, y_scale, z_scale;
double   x_off, y_off, z_off;
double   x_min, y_min, z_min;
double   x_max, y_max, z_max;
};
#pragma pack(pop)
#pragma pack(push, 1)
struct PointFormat1
{
uint32_t x, y, z;
uint16_t intensity;
uint8_t  return_info;
uint8_t  classification;
uint8_t  scan_angle_rank;
uint8_t  user_data;
uint16_t point_src_id;
double   gps_time;
};
#pragma pack(pop)
void read(const std::string &path);
};

附言:我知道libLAS,我正在努力让它工作,但我目前无法安装它。

LAS格式规范使用带符号的32位整数作为LAS点数据格式记录1中的x/y/z值:http://www.asprs.org/wp-content/uploads/2019/07/LAS_1_4_r15.pdf

在PointFormat1结构中,切换到int32_t,它就可以工作了。

最新更新