微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 C++ 读取 .las 1.3 版,并使用 pcl 库显示结果

如何解决使用 C++ 读取 .las 1.3 版,并使用 pcl 库显示结果

我对点云世界还很陌生。此外,我对 C++ 的经验并不多。 我需要读取 .las 文件并使用 pcl 库处理它们。 This 是我需要读取的数据集中的示例文件。我跟着this youtube video。但是,由于我尝试读取的文件是 1.3 版,I followed the corresponding spec file 用于定义标题字段,并且我使用了“数据记录格式 3”,这是文件标题中提到的数据记录格式。

这是我对标题和数据记录格式的定义:

#pragma once
#include <string>
#include <vector>

struct float4
{
    float x,y,z,intensity;
};

class PointCloud
{
    public:

        uint32_t getVertsCount();
        float4* getVertsData();

        template<typename PointT>
        typename pcl::PointCloud<PointT>::Ptr read(const std::string& path);//void read(const std::string &path);

    private:
        std::vector<float4> verts;
        #pragma pack(1)
        struct Header
        {
            char magic[4];
            uint16_t fileSourceID;
            uint16_t globalEncoding;
            uint32_t guidData1;
            uint16_t guidData2;
            uint16_t guidData3;
            uint8_t guidData4[8];
            uint8_t versionMaj,versionMin;
            char systemIdentifier[32];
            char genSoftware[32];
            uint16_t creationDay,creationYear;
            uint16_t headerSize;
            uint32_t pointDataOffset;
            uint32_t numVarLenRecords;
            uint8_t pointDataRecordFormat;
            uint16_t pointDataRecordLen;
            uint32_t numberOfPoints;
            uint32_t numPointsByReturn[5];
            double scaleX,scaleY,scaleZ;
            double offsetX,offsetY,offsetZ;
            double maxX,minX,maxY,minY,maxZ,minZ;
            uint64_t waveform;
        };
        
        //#pragma pack(1)
        struct PointRecord3
        {
            uint32_t x,z;
            uint16_t intensity;
            uint8_t flags;
            uint8_t classification;
            uint8_t scanAngleRank;
            uint8_t userData;
            uint16_t pointSourceId;
            double gpsTime;
            uint16_t red;
            uint16_t green;
            uint16_t blue;
        };
};

我用下面的代码读取了点数据,但是没有得到正确的点:

template<typename PointT>
typename pcl::PointCloud<PointT>::Ptr PointCloud::read(const string& path)
{
    ifstream inf(path,ios::binary);
    typename pcl::PointCloud<PointT>::Ptr lasCloud(new pcl::PointCloud<PointT>);

    if (inf.is_open())
    {
        Header header;
        inf.read((char*)&header,sizeof(header));
        
        cout << "Signature: " << header.magic << endl;
        cout << "Source ID: " << int(header.fileSourceID) << endl;
        cout << "Global Encoding: " << int(header.globalEncoding) << endl;
        cout << "Guid 1: " << int(header.guidData1) << endl;
        cout << "Guid 2: " << int(header.guidData2) << endl;
        cout << "Guid 3: " << int(header.guidData3) << endl;
        cout << "Guid 4: " << header.guidData4 << endl;
        cout << (int)header.versionMaj << '.' << (int)header.versionMin << endl; 
        cout << "Sys Identifier: " << header.systemIdentifier << endl;
        cout << "Gen Software: " << header.genSoftware << endl;
        cout << "Creation Day: " << header.creationDay << endl;
        cout << "Creation Year: " << header.creationYear << endl;
        cout << header.headerSize << " == " << sizeof(header) << endl;
        cout << "Point Data Offset: " << header.pointDataOffset << endl;
        cout << "Number of Variable Len Records: " << header.numVarLenRecords << endl;
        cout << "point Data Record Format: " << header.pointDataRecordFormat << endl;
        cout << "point Data Record Len: " << header.pointDataRecordLen << endl;
        cout << "Number of Points: " << header.numberOfPoints << endl;
        cout << "Number of Points by Return: " << header.numPointsByReturn << endl;
        cout << "Scales: " << header.scaleX << "," << header.scaleY << "," << header.scaleZ << endl;
        cout << "Offsets: " << header.offsetX << "," << header.offsetY << "," << header.offsetZ << endl;
        cout << "Xmin = " << header.minX << ",Ymin = " << header.minY << ",Zmin = " << header.minZ << endl;
        cout << "Xmax = " << header.maxX << ",Ymax = " << header.maxY << ",Zmax = " << header.maxZ << endl;
        cout << "Waveform: "<<header.waveform << endl;

        assert(header.versionMaj == 1 && header.versionMin == 3);
        //assert(header.headerSize == sizeof(header));
        assert(header.pointDataRecordFormat == 3);

        //inf.seekg(header.pointDataOffset);
        inf.seekg(sizeof(header));
        //inf.seekg(header.pointDataOffset+sizeof(header.waveform));
        for (uint32_t i = 0; i < header.numberOfPoints; i++)
        {
            //PointRecord1* points = new PointRecord1[header.numberOfPoints];
            PointRecord3 point;
            //inf.read((char*)(points + i),sizeof(PointRecord1));
            //inf.read((char*)&point,sizeof(PointRecord1));
            inf.read((char*)&point,sizeof(PointRecord3));

            PointT cloudPoint;
            cloudPoint.x = (float)(point.x * header.scaleX) + header.offsetX;
            cloudPoint.y = (float)(point.y * header.scaleY) + header.offsetY;
            cloudPoint.z = (float)(point.z * header.scaleZ) + header.offsetZ;
            cloudPoint.intensity = (float)(point.intensity) / 65536.0;
            lasCloud->points.push_back(cloudPoint);
        }
        
        if (!inf.good())
            throw runtime_error("Reading went wrong!");

    }
    else
    {
        throw runtime_error("Can't find any!");
    }

    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::PointXYZI>::Ptr inputCloudI; //
    PointCloud  pcd;
    inputCloudI=pcd.read<pcl::PointXYZI>("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();
    }

}

我注意到了一个问题。标头大小定义为 227(这是标头大小字段的值)。但是,在报头的末尾有一个名为“波形数据包记录开始”的 8 字节字段,如果包含在报头定义中,则报头大小为 235 字节。此外,用于在 youtube 视频中查找点数据的 pointDataOffset 字段指向 227 字节。当我用它来寻找点数据时,我得到了不合理的点值。 我的目标是处理这个点云并使用 pcl 云显示它,但我无法正确读取这些点。

解决方法

我不知道 Lidar 和 *.las 文件,但我注意到输入文件是用 libLAS 创建的

> file 20180524_I65_NB_RoadSurface_1_50.5.las 
20180524_I65_NB_RoadSurface_1_50.5.las: LIDAR point data records,version 1.3,SYSID libLAS,Generating Software libLAS 1.6.0

那么,为什么不使用 libLAS 来读取数据呢? https://liblas.org/

libLAS 带有方便的 CLI 实用程序来处理 las 文件,例如:

lasinfo 20180524_I65_NB_RoadSurface_1_50.5.las 
---------------------------------------------------------
  Header Summary
---------------------------------------------------------

  Version:                     1.3
  Source ID:                   0
  Reserved:                    0
  Project ID/GUID:             '00000000-0000-0000-0000-000000000000'
  System ID:                   'libLAS'
  Generating Software:         'libLAS 1.6.0'
  File Creation Day/Year:      144/2018
  Header Byte Size             227
  Data Offset:                 227
  Header Padding:              0
  Number Var. Length Records:  None
  Point Data Format:           3
  Number of Point Records:     22017565
  Compressed:                  False
  Number of Points by Return:  0 0 0 0 0 
  Scale Factor X Y Z:          0.00100000000000 0.00100000000000 0.00100000000000
  Offset X Y Z:                590284.000 4339456.000 157.000
  Min X Y Z:                   589879.772 4338728.975 149.667
  Max X Y Z:                   590334.248 4339568.021 178.397
  Spatial Reference:           None

---------------------------------------------------------
  Schema Summary
---------------------------------------------------------
  Point Format ID:             3
  Number of dimensions:        16
  Custom schema?:              false
  Size in bytes:               34

  Dimensions
---------------------------------------------------------
  'X'                            --  size: 32 offset: 0
  'Y'                            --  size: 32 offset: 4
  'Z'                            --  size: 32 offset: 8
  'Intensity'                    --  size: 16 offset: 12
  'Return Number'                --  size: 3 offset: 14
  'Number of Returns'            --  size: 3 offset: 14
  'Scan Direction'               --  size: 1 offset: 14
  'Flightline Edge'              --  size: 1 offset: 14
  'Classification'               --  size: 8 offset: 15
  'Scan Angle Rank'              --  size: 8 offset: 16
  'User Data'                    --  size: 8 offset: 17
  'Point Source ID'              --  size: 16 offset: 18
  'Time'                         --  size: 64 offset: 20
  'Red'                          --  size: 16 offset: 28
  'Green'                        --  size: 16 offset: 30
  'Blue'                         --  size: 16 offset: 32
  
---------------------------------------------------------
  Point Inspection Summary
---------------------------------------------------------
  Header Point Count: 22017565
  Actual Point Count: 22017565

  Minimum and Maximum Attributes (min,max)
---------------------------------------------------------
  Min X,Y,Z:      600191.027,4313816.564,148.621
  Max X,Z:      600212.594,4314678.007,156.632
  Bounding Box:     600191.027,600212.594,4314678.007
  Time:         55449082.421688,55488872.904376
  Return Number:    0,0
  Return Count:     0,0
  Flightline Edge:  0,0
  Intensity:        0,255
  Scan Direction Flag:  0,0
  Scan Angle Rank:  0,0
  Classification:   1,3
  Point Source Id:  0,31
  User Data:        0,0
  Minimum Color (RGB):  0 0 0 
  Maximum Color (RGB):  0 0 0 

  Number of Points by Return
---------------------------------------------------------
    (1) 22017565

  Number of Returns by Pulse
---------------------------------------------------------
    (0) 22017565

  Point Classifications
---------------------------------------------------------
    7187055 Unclassified (1) 
    8128678 Ground (2) 
    6701832 Low Vegetation (3) 
  -------------------------------------------------------
    0 withheld
    0 keypoint
    0 synthetic
  -------------------------------------------------------

las2txt 20180524_I65_NB_RoadSurface_1_50.5.las  qq.txt && head qq.txt
600209.243,4313837.086,155.155
600209.342,4313839.620,155.191
600209.232,4313836.806,155.154
600209.338,4313839.516,155.197
600209.221,4313836.523,155.165
600209.333,4313839.398,155.194
600209.206,4313836.177,155.158
600209.328,4313839.285,155.200
600209.189,4313835.778,155.145
600209.322,4313839.152,155.193

这意味着文件没问题,库工作正常,您将节省很多时间学习基本的库使用,而不是尝试自己重新实现它(想想各种数据格式等.、错误处理等、测试等、在出现问题时获得反馈等,以及您的时间)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。