>  翔翔

一、激光点云介绍

在同一空间参考系下表达目标空间分布和目标表面光谱特性的海量点集合,是由物体模型表面上一系列空间采样点构成的模型几何描述,也是三维激光扫描数据的通用表现形式。
●Pi = { Xi,Yi,Zi,……. }表示空间中的一个点。
●Point Cloud = { P1,P2, P3,…..Pn }表示一组点云数据。
点云数据中包含了每个点的经纬度坐标、强度、多次回波、颜色等丰富的信息(关于点云的信息特征后期会具体讲解),在测绘、林业、农业、数字城市等领域均有相关应用。
常见LiDAR点云数据格式类型如下:

数据格式 简介 说明
ASCⅡ

txt、xyz、pts、csv

记录方式灵活,读写方便,各类硬件设备普遍采用的一种数据格式

但是,数据读取较慢,占用空间较大,面对海量点云数据,存储和处理较困难,且LiDAR特有的数据信息丢失

LAS

目前通用的点云数据格式,由美国摄影测量与遥感协会提出(LAS1.0、1.1、1.2、1.3、1.4)

开放的二进制数据格式,具有规定的文件头结构和数据组织,能够包含更多的信息,并且占用的存储空间相对较小。

但是,读写需要专业软件

上诉格式也是超图支持的格式。本文着重讲述LAS格式的点云数据处理。

二、代码剖析

简单了解激光点云数据后,从本节开始就着重介绍下,如何读取Las中自带的坐标系,以及将激光点云数据处理成三维瓦片格式。

2.1  LAS数据坐标系获取

前人栽树后人乘凉,本文在获取LAS数据的坐标系也是站在巨人的肩旁上实现的。具体的可以参考该案例库:GitHub - mreutegg/laszip4j: The LASzip library ported to Java

在LAS数据中如果数据有存储坐标系,那么通常是存储在Variable Length Records(可变长度记录)。所以要获取坐标系就需要获取可变长度记录中的数据,获取的关键代码如下:

lasVLRs[i].data = new byte[lasVLRs[i].record_length_after_header];
stream.getBytes(lasVLRs[i].data, lasVLRs[i].record_length_after_header);

此时获取出来的坐标系是WKT格式的坐标系,具体的WKT坐标系说明可参考:OGC WKT坐标系问题 — GDAL 文档。超图在可将WKT坐标系转成对应的坐标系(PrjCoordSys),转换方法如下:

PrjCoordSys prj = new PrjCoordSys();
for (int i = 0; i < lasVLRs.length; i++) {
    String wkt = new String(lasVLRs[i].data, "utf-8");
    String wkttempfilepath = "wkt.prj";
    File wkttempfile = new File(wkttempfilepath);
    if (wkttempfile.exists()) {
        wkttempfile.delete();
    }
    wkttempfile.createNewFile();
    FileWriter fileWritter = new FileWriter(wkttempfile.getName(), true);
    BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
    bufferWritter.write(wkt);
    bufferWritter.close();
    if (prj.fromFile(wkttempfilepath, PrjFileType.ESRI)) {
        if (prj.getEPSGCode() != 0) {
            break;
        }
    }
    wkttempfile.delete();
}
return prj;

至此,获取坐标系并转换的操作就完成了。

2.2  LAS数据生成三维瓦片

我们先上LAS格式的点云数据生成三维瓦片的代码:

PointCloudFileInfo info = new PointCloudFileInfo();
/**
 * 设置点云生成的las文件,这里的las文件需要按照这里设置为准。一个名字下面可以有多个las文件。
 */
HashMap<String, ArrayList<String>> groupMap = new HashMap<>();
ArrayList<String> lasfiles = new ArrayList<>();
lasfiles.add(m_txtLasFile.getText().trim());
groupMap.put("group", lasfiles);
info.setGroupFileNames(groupMap);
/**
 * 设置坐标系
 */
PrjCoordSys prj = PrjCoordSys.fromEPSG(epsg);
info.setSrcPrjCoordSys(prj);
/**
 * 设置点云数据单位,如果坐标系是经纬度那么设置为度。如果坐标系是投影坐标系或者是平面无投影,此时设置为米。如果有其他单位请在此修改代码
 */
if (prj.getType() == PrjCoordSysType.PCS_EARTH_LONGITUDE_LATITUDE) {
    info.setPointDataUnit(DataUnit.Degree);
} else {
    info.setPointDataUnit(DataUnit.Meter);
}
/**
 * 设置点云数据参考点,如果数据没有参考点,那么默认为0,如果有参考点,那么以实际参考点维准
 */
Point3D position = new Point3D(Double.valueOf(m_txtX.getText().trim()), Double.valueOf(m_txtY.getText().trim()), Double.valueOf(m_txtZ.getText().trim()));
info.setPosition(position);

PointCloudCacheBuilder cacheBuilder = new PointCloudCacheBuilder();
/**
 * 设置点云瓦片的名称
 */
cacheBuilder.setCacheName(m_txtLasCacheName.getText().trim());
/**
 * 设置点云文件的配置信息
 */
cacheBuilder.setPointCloudInfos(info);
/**
 * 设置S3M的版本,这里默认以3.0,该模式也是目前最优的选择
 */
cacheBuilder.setCacheVersion(S3MVersion.VERSION_30);
/**
 * 设置瓦片文件类型,这里最优选择是S3MB
 */
cacheBuilder.setFileType(CacheFileType.S3MB);
/**
 * 设置集合压缩类型,此时选择DRACO。该压缩类型是与S3M3.0配套使用,保证后续浏览性能,但是会增加生成瓦片时间
 */
cacheBuilder.setGeometryCompressType(MeshCompressType.DRACO);
/**
 * 设置点云瓦片的输出路径
 */
cacheBuilder.setOutputFolder(m_txtOutputPath.getText().trim());
/**
 * 设置生成瓦片的处理模式,这里最好选择追加模式
 */
cacheBuilder.setProcessType(ProcessFileType.ADD);
/**
* 设置点云数据特征值字段,根据界面选择设置对应的特征值。
* 强度:INTENSITY
* 类别:CLASSIFY,如果选择类别此范例中默认是全部类别,如果要获取类别并设置制定类别,代码如下;
* cacheBuilder。getValidClassifyInfos(string)
* PointCloudFileInfo.setArrClassify([])
* 高度:POSZ
*/
PointCloudCategoryField field = m_cmbType.getSelectedItem().equals("高度") ? PointCloudCategoryField.POSZ : m_cmbType.getSelectedItem().equals("类别") ? PointCloudCategoryField.CLASSIFY : PointCloudCategoryField.INTENSITY;
cacheBuilder.setCategoryField(field);
/**
 * 设置耽搁Tile的镜子塔剖分方式,默认设置为四叉树。如果点云数据的高度相差特别大此时需要用八叉树,如果高度相差不大,此时选择四叉树.
 */
cacheBuilder.setTilePyramidSplitType(PyramidSplitType.QuadTree);

mainPanel.setCursor(new Cursor(3));
if (cacheBuilder.build()) {
    JOptionPane.showMessageDialog(null, "点云数据生成瓦片成功");
} else {
    JOptionPane.showMessageDialog(null, "点云数据生成瓦片失败");
}
maiPanel.setCursor(new Cursor(0));

上诉的代码中都有详细的注释说明。具体参数说明可参考上诉说明以及iObjects Java组件的帮助文档说明。

2.3 操作展示:

2.4 源码

https://gitee.com/bazingaga/SuperMap-PointCloudCache

https://github.com/songxiang/SuperMap-PointCloudCache

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐