前言
LAS格式是美国摄影测量与遥感协会(ASPRS)下属的LiDAR委员会制定的标准LiDAR数据格式,该格式是目前最常用的LiDAR数据存储格式。LAS文件里包含3个部分(头数据块、变长数据记录区和点数据记录区),具体意义在格式说明里都有详细讲解就不在这里赘述了。
不管是车载LiDAR、还是机载LiDAR,采集的点云数据都具有海量性,这也导致las数据文件常常有几个GB大小(甚至更大),其中包含的离散点数据能达到(千万以上)。若不对原始数据做金字塔处理,一般的硬件设备或常用的软件都不具备显示或编辑这样的数据能力,而金字塔处理方法目前还未发现开源代码可供学习(若有,还请提醒一下共同学习),但是可以采用将大数据量的las文件,分割成若干个小数据量的las或者文本文件(txt),这样就可以在普通硬件、软件和自己的程序里进行显示和处理了。下面笔者将对如何从大数据las文件分割成若干小数据量文本文件进行讲解,最后制作一个小的应用供大家使用。
实验数据介绍
数据为las格式,大小1.79GB,包含5600万离散点。
libLAS库的编译和配置
在前面博客中已有详细讲解,请参考。
代码及含义
利用C++语言读写las文件,在liblas库的官网上有详细的介绍,感兴趣的可以学习。官网链接:http://www.liblas.org/tutorial/cpp.html#reading-las-data-using-liblas-reader
lasfilesegment.h
#include <iostream>
#include <string>
//************************************
// ClassName: LasFileSegment
// Date: 2016/04/29
// Author: Mr.Shi
// Contact: ***
//************************************
class LasFileSegment
{
std::string inFileName_; //文件名
public:
LasFileSegment(){};
void setFileName(std::string _inFileName){ //设置读入文件名
inFileName_=_inFileName;
}
//************************************
// Method: fileSegment
// FullName: LasFileSegment::fileSegment
// Access: public
// Returns: void
// Qualifier:
// function: 将las文件分割成1000万点一份的txt数据
//************************************
void fileSegment(); //文件分割
};
lasfilesegment.cpp
#include <liblas\liblas.hpp>
#include <iomanip>
#include <sstream>
#include "lasfilesegment.h"
void LasFileSegment::fileSegment()
{
std::ifstream ifs;
ifs.open(inFileName_, std::ios::in | std::ios::binary);
if (ifs == NULL)
{
std::cout<<"File Error!"<<std::endl;
return;
}
liblas::ReaderFactory f ;
liblas::Reader reader = f.CreateWithStream(ifs); //
liblas::Header const& header = reader.GetHeader(); //las文件头数据块信息
std::cout<<"Number of point records : "<<header.GetPointRecordsCount()<<std::endl; //记录的点数信息,下面的信息比较重要,都列出来了,具体意思也比较好理解
std::cout<<"File Signature (“LASF”) : "<<header.GetFileSignature()<<std::endl;
std::cout<<std::setiosflags(std::ios::fixed); //设置显示小数点后9位小数。
std::cout<<std::setprecision(9)<<"X scale factor : "<<header.GetScaleX()<<std::endl;
std::cout<<"Y scale factor : "<<header.GetScaleY()<<std::endl;
std::cout<<"Z scale factor : "<<header.GetScaleZ()<<std::endl;
std::cout<<"X offset : "<<header.GetOffsetX()<<std::endl;
std::cout<<"Y offset : "<<header.GetOffsetY()<<std::endl;
std::cout<<"Z offset : "<<header.GetOffsetZ()<<std::endl;
std::cout<<"Max X : "<<header.GetMaxX()<<std::endl;
std::cout<<"Max Y : "<<header.GetMaxY()<<std::endl;
std::cout<<"Max Z : "<<header.GetMaxZ()<<std::endl;
std::cout<<"Min X : "<<header.GetMinX()<<std::endl;
std::cout<<"Min Y : "<<header.GetMinY()<<std::endl;
std::cout<<"Min Z : "<<header.GetMinZ()<<std::endl;
reader.ReadPointAt(0); //点集记录区中的信息
liblas::Point const& p = reader.GetPoint();
std::cout<<"X :"<<p.GetX()<<std::endl;
std::cout<<"Y :"<<p.GetY()<<std::endl;
std::cout<<"Z :"<<p.GetZ()<<std::endl;
std::cout<<"Intensity :"<<p.GetIntensity()<<std::endl;
std::cout<<"Return Number :"<<p.GetReturnNumber()<<std::endl;
std::cout<<"Number of Returns :"<<p.GetNumberOfReturns()<<std::endl;
std::cout<<"Classification :"<<p.GetClassification()<<std::endl;
std::cout<<"Scan Direction Flag :"<<p.GetScanDirection()<<std::endl;
std::cout<<"Edge of Flight Line :"<<p.GetFlightLineEdge()<<std::endl;
std::cout<<"Scan Angle Rank :"<<p.GetScanAngleRank()<<std::endl;
std::cout<<"Point Source ID :"<<p.GetPointSourceID()<<std::endl;
std::cout<<"GPS Time :"<<p.GetTime()<<std::endl;
char path_buffer[_MAX_PATH]; //获取文件路径
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath( inFileName_.c_str(), drive, dir, fname, ext );
std::string driveStr(drive),dirStr(dir);
std::string outFilePath(driveStr+dirStr);
std::cout<<outFilePath;
std::string currentFileName("0.txt");
std::ofstream ofile;
ofile.open(outFilePath+currentFileName);
ofile<<"//X Y Z Intensity ReturnNumber NumberofReturns Classification ScanDirectionFlag EdgeofFlightLine ScanAngleRank PointSourceID GPSTime\n";
int num(0),count(0);
reader.Seek(0);
while (reader.ReadNextPoint()) //每个1000万对数据进行一次保存
{
liblas::Point const& p = reader.GetPoint();
ofile<<std::setiosflags(std::ios::fixed);
ofile<<std::setprecision(8)<<p.GetX()<<" "<<p.GetY()<<" "<<p.GetZ()<<" "<<p.GetIntensity()<<" "
<<p.GetReturnNumber()<<" "<<p.GetNumberOfReturns()<<" "<<p.GetClassification()<<" "
<<p.GetScanDirection()<<" "<<p.GetFlightLineEdge()<<" "<<p.GetScanAngleRank()<<" "
<<p.GetPointSourceID()<<" "<<p.GetTime()<<std::endl;
if (++num%10000000==0)
{
++count;
ofile.close();
std::stringstream ss;
std::string currentFileName;
ss<<count;
ss>>currentFileName;
ofile.open(outFilePath+currentFileName+".txt");
ofile<<"//X Y Z Intensity ReturnNumber NumberofReturns Classification ScanDirectionFlag EdgeofFlightLine ScanAngleRank PointSourceID GPSTime\n";
}
}
ofile.close();
}
main.cpp
#include "lasfilesegment.h"
int main()
{
std::string inFileName;
std::cout<<"Input inFileName:\n";
std::cin>>inFileName;
LasFileSegment lfs;
lfs.setFileName(inFileName);
lfs.fileSegment();
return 1;
}
控制台显示
使用Qt库为刚才写的代码加个简单界面
应用下载连接(使用环境64位系统):http://pan.baidu.com/s/1c1AMtaC