使用Python读取las点云,写入las点云,无损坐标精度

目录

  • 1 为什么要写这个博文
  • 2 提出一些关键问题
  • 3 给出全部代码
    • 安装依赖
    • 源码(laspy v2.x)

1 为什么要写这个博文

搜索使用python读写las点云数据,可以找到很多结果。但是! 有些只是简单的demo,且没有发现/说明可能遇到的问题;有些晦涩难懂,不够实用主义;有些须付费观看,没有开源精神。

本人在使用laspy v2.3读写点云文件时,着实被坐标精度问题难到了,顺便就仔细学习了下las格式到底是什么来头。

您猜怎么着,如果能打开这个网址,都在这里面详细说明了:laspy document

我还是种个树吧,直接拔了就能用。文末贴源码。

2 提出一些关键问题

  1. 注意:
    * 实测版本 laspy v2.3,2.x版本应该都可用,但不适合1.x版本。
    * las 存储数据时,需要设置 scales 和 offsets,否则会出现精度问题。
    * las 存储颜色时,数值类型为 16 位无符号整型。rgb = (normal_rgb * 65535).astype(np.uint16)

  2. las 格式原生支持的属性字段,与las版本密切相关。官方说明:https://laspy.readthedocs.io/en/latest/intro.html#point-records

  3. 对 scales 和 offsets 的理解:
    比例scales 表明数据的准确性。 0.001 是毫米精度。这意味着如果您的坐标是 0.123456,它将被限制为 0.123。
    偏移offset 的目的是避免整数溢出。假设您要存储 123456789.123。在 LAS 文件中,您实际上将存储一个整数:123456789123,该整数将在读取时使用比例因子转换为 123456789.123。但 123456789123 比 32 位整数所能存储的要大得多。因此存储时,将该值偏移 123450000,实际存的是6789123。
    (6789123 * 0.001 + 123450000 = 123456789.123)
    段落出处

3 给出全部代码

安装依赖

使用 pip (# 选择一个安装就好):

# Install _without_ LAZ support
pip install laspy# Install with LAZ support via lazrs
pip install laspy[lazrs]# Install with LAZ support via laszip
pip install laspy[laszip]# Install with LAZ support via both lazrs & laszip
pip install laspy[lazrs,laszip]

使用 conda (# 选择一个安装就好):

conda install -c conda-forge laspy
conda install -c conda-forge lazrs-python

源码(laspy v2.x)

三个工具函数:
read_las_fit() : 读取 las 文件
write_las_fit(): 保存 las 文件
get_las_header_attrs() : 获取不同 las 版本支持的固有属性
备注:_fit 的意思是,可以支持各种属性信息的读取和写入

import laspy
import numpy as npdef read_las_fit(filename, attrs=None):"""读取 las 文件,获取三维坐标 xyz, 颜色 rgb, 属性 attr_dict。当文件没有 RGB 信息时,返回全0的 RGB 信息Args:filename: <str> las 文件路径attrs: <list> 需要额外获取的属性信息 如 ['label']Returns:xyz, rgb, attr_dict"""if attrs is None:attrs = []# 默认返回 scales, offsets ,合并 ["scales", "offsets"]attrs = list(set(attrs + ["scales", "offsets"]))# 读取点云inFile = laspy.read(filename)# inFile.point_format.dimensions可以获取所有的维度信息N_points = len(inFile)x = np.reshape(inFile.x, (N_points, 1))y = np.reshape(inFile.y, (N_points, 1))z = np.reshape(inFile.z, (N_points, 1))xyz = np.hstack((x, y, z))# TODO 注意。如果是大写的 X Y Z,需要转换后才是真实坐标: real_x = scale[0] * inFile.X + offset[0]# 初始化 rgb 全是 0rgb = np.zeros((N_points, 3), dtype=np.uint16)if hasattr(inFile, "red") and hasattr(inFile, "green") and hasattr(inFile, "blue"):r = np.reshape(inFile.red, (N_points, 1))g = np.reshape(inFile.green, (N_points, 1))b = np.reshape(inFile.blue, (N_points, 1))# i = np.reshape(inFile.Reflectance, (N_points, 1))rgb = np.hstack((r, g, b))else:print(f"注意:{filename.split('/')[-1]} 没有RGB信息,返回全0的RGB信息!")# 组织其他属性信息attr_dict = {}for attr in attrs:# 先判断 header 中是否有该属性if hasattr(inFile.header, attr):value = getattr(inFile.header, attr)if hasattr(value, "array"):attr_dict[attr] = np.array(value)else:attr_dict[attr] = value# 再判断 是否为额外属性elif hasattr(inFile, attr):value = getattr(inFile, attr)if hasattr(value, "array"):attr_dict[attr] = np.array(value)else:attr_dict[attr] = valueelse:attr_dict[attr] = Noneprint(f"注意:{filename.split('/')[-1]} 没有属性 {attr} 信息!")return xyz, rgb, attr_dictdef write_las_fit(out_file, xyz, rgb=None, attrs=None):"""将点云数据写入 las 文件,支持写入 坐标xyz, 颜色rgb, 属性attrsArgs:out_file: 输出文件路径xyz: 点云坐标 ndarray (N, 3)rgb: 点云颜色 ndarray (N, 3)attrs:固有属性:file_source_id, gps_time, Intensity, Number of Returns, ....额外属性:label, pred, ...注意:如果不传入 scales 和 offsets,则会自动计算Returns:"""if attrs is None:attrs = {}# 1. 创建 las 文件头。point_format和version决定了las支持哪些固有属性# 详情见 https://pylas.readthedocs.io/en/latest/intro.html?highlight=red#point-recordsheader = laspy.LasHeader(point_format=7, version="1.4")  # 7 支持rgb# 自动计算 scales 和 offsets,确保坐标精度无损# https://stackoverflow.com/questions/77308057/conversion-accuracy-issues-of-e57-to-las-in-python-using-pye57-and-laspyif "offset" not in attrs:min_offset = np.floor(np.min(xyz, axis=0))attrs["offset"] = min_offsetif "scales" not in attrs:attrs["scales"] = [0.001, 0.001, 0.001]  # 0.001 是毫米精度# 初始化一些需要保存的属性值。如果是固有属性,直接赋值; 如果是额外属性,添加到 header 中, 后续赋值extra_attr = []for attr, value in attrs.items():if hasattr(header, attr):  # 设置固有的属性的值, 如 scales, offsetsheader.__setattr__(attr, value)else:  # 添加额外属性,在 las 初始化后赋值header.add_extra_dim(laspy.ExtraBytesParams(name=attr, type=np.float32))extra_attr.append(attr)# 2. 创建 las 文件las = laspy.LasData(header)# 添加xyz坐标las.x = xyz[:, 0]las.y = xyz[:, 1]las.z = xyz[:, 2]# 添加RGB颜色,如果是归一化的颜色,则需要乘以 65535,转为 uint16if rgb is not None:if np.max(rgb) <= 1:rgb = (rgb * 65535).astype(np.uint16)  # 65535 = 2^16 - 1, las存储颜色是16位无符号整型las.red = rgb[:, 0]las.green = rgb[:, 1]las.blue = rgb[:, 2]# 添加额外属性for attr in extra_attr:# 当 value 是 n * 1 的 ndarray 时,转换为 1 维数组value = attrs[attr]if value.ndim == 2 and value.shape[1] == 1:value = value.flatten()las[attr] = value# 保存LAS文件las.write(out_file)def get_las_header_attrs(point_format=7, version="1.4"):"""根据 point_format 和 version 获取 las 文件的 header 属性说明文档:https://laspy.readthedocs.io/en/latest/intro.html#point-recordsArgs:point_format: 点格式version: 版本Returns:"""dimensions = []header = laspy.LasHeader(point_format=point_format, version=version)  # 7 支持rgbfor dim in header.point_format.dimensions:dimensions.append(dim.name)return dimensionsif __name__ == '__main__':# 测试1: 获取 las 文件头属性fields = get_las_header_attrs(7, "1.4")print(f"point_format=7, version=1.4, 头文件包含字段: {fields}")# 测试2: 读取LAS文件read_las_path = "/path_2_data/one_point_cloud.las"xyz_, rgb_, attrs_ = read_las_fit(read_las_path, ["scales", "offsets"])print(attrs_)# 测试3: 写入LAS文件save_las_path = "/path_2_data/one_point_cloud_fit.las"write_las_fit(save_las_path, xyz_, rgb_, {# "scales": attrs_["scales"],# "offsets": attrs_["offsets"]})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/834507.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【第16章】spring-mvc之多文件上传

文章目录 前言一、文件大小限制二、前端三、后端总结 前言 本章在上篇文件的上传基础上就行扩展,多文件上传、多线程处理&#xff0c;所有的文件上传成功则返回成功。 一、文件大小限制 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns…

震惊,现在面试都加科技与狠货了

震惊&#xff0c;现在面试都加科技与狠货了 生成式AI盛行的现在&#xff0c;程序员找工作变容易了吗我和老痒喝着大酒&#xff0c;吃着他的高升宴&#xff0c;听他说他面试的各种细节&#xff0c;老狗我只恨自己动作慢了一步&#xff0c;不然现在在那侃侃而谈的就是我了。 面试…

守护数字疆域:2024年网络安全报告深度解读

在这个数据如潮涌动的数字时代&#xff0c;每一比特信息都可能是攻防双方角力的战场。《Check Point 2024年网络安全报告》不但为我们揭示了过去一年网络安全世界的风云变幻&#xff0c;更以前瞻性的视角勾勒出未来的挑战与机遇。此刻&#xff0c;让我们携手深潜这份权威指南的…

Redis-6 三种集群模式:主从模式、哨兵模式、分片集群

主从模式 一.介绍一下redis的主从同步 单节点的redis的并发能力是有上限的&#xff0c;要实现高并发&#xff0c;就要搭建主从集群&#xff0c;实现读写分离。通常是一主多从&#xff0c;主节点负责写数据&#xff0c;从节点负责读数据。 二.介绍一下主从模式同步数据的流程…

GIS找工作:天津测绘院24届春招Offer面经

本文介绍2024届春招中&#xff0c;天津市测绘院有限公司的1场面试的提问问题&#xff0c;以及后续体检环节的相关流程等。 2024年04月投递了天津市测绘院有限公司的软件开发类岗位&#xff0c;暂不清楚所在部门。目前完成了一面&#xff0c;并有幸获得Offer&#xff1b;在这里记…

分位数回归的基本原理和特点

基本模型及解释 分位数回归经典模型是由Koenker和Bassett (1978b)引入的&#xff0c;它从位置模型中的普通分位数(也称为“百分位数”)的概念扩展到更一般的一类线性模型&#xff0c;其中条件分位数具有线性形式。为了简单地回忆一下普通分位数&#xff0c;考虑一个实数随机变…

QGraphicsView实现简易地图11『指定层级-定位坐标』

前文链接&#xff1a;QGraphicsView实现简易地图10『自适应窗口大小』 提供一个地图初始化函数&#xff0c;指定地图显示的中心点和地图缩放层级 能够让地图显示某一层级的瓦片&#xff0c;并将中心点坐标显示在视图中心。 1、动态演示效果 7级地图-大连-老虎滩 定位到 8级地图…

java中建造者模式和模版模式的区别?可以用代码实例说明

建造者模式&#xff08;Builder Pattern&#xff09;和模板模式&#xff08;Template Pattern&#xff09;在Java中都是行为设计模式&#xff0c;但它们的用途和目的有所不同。以下是两者的主要区别&#xff0c;并通过代码实例来说明。 建造者模式&#xff08;Builder Pattern…

双展联动—第四届中国跨境电商及新电商交易博览会强势来袭

双展联动产业升级 ——第四届中国跨境电商及新电商交易博览会强势来袭 万商云集有福之州&#xff0c;掘金万亿蓝海市场。备受瞩目的“第四届中国跨境电商及新电商交易博览会暨2024中国户外生活及休闲运动用品交易博览会”将于2024年9月21-23日在福建福州海峡国际会展中心盛大召…

【数据库】存储过程、函数、触发器

按照要求实现员工管理数据库系统中的指定操作&#xff1a;1、创建一个数据库 staff&#xff0c;并在数据库中创建以下四张表&#xff1a; 员工表 employee&#xff08;员工编号id,姓名userName,出生日期birthDate,身份证号idCard,登录名称loginName,登录密码password,手机号mo…

基于Vite创建项目

1.npm设置镜像源为国内淘宝源 npm config set registry https://registry.npmmirror.com 2.vite官方中文文档 Vite | 下一代的前端工具链 3.创建项目 npm create vitelatest my-app 接下来按照提示操作就可以&#xff0c;最后 npm run dev 就可以启动项目了 4.安装依赖 …

接口性能测试 —— Jmeter并发与持续性压测!

接口压测的方式&#xff1a; 1、同时并发&#xff1a;设置线程组、执行时间、循环次数&#xff0c;这种方式可以控制接口请求的次数 2、持续压测&#xff1a;设置线程组、循环次数&#xff0c;勾选“永远”&#xff0c;调度器&#xff08;持续时间&#xff09;&#xff0c;这种…

汽车电子零部件(13):BMS电池管理系统

前言: 电池管理系统(BMS)确保电动汽车(EV)的能量分配安全高效。目前流行电动汽车中使用的有四种主要BMS架构,BMS与充电基础设施互为集成关系。BMS主要管理 的是电池组,电池组由很多电芯组成,比如下图是H/EV电池组的主要部件,显示了电池、连接、控制电路和包装的总体布…

软件技术主要学什么课程

软件技术专业主要学习的课程和内容有编程语言、数据结构与算法、数据库技术等&#xff0c;以下是上大学网( www.sdaxue.com)整理的软件技术主要学什么课程&#xff0c;供大家参考&#xff01; 编程语言&#xff1a;掌握一种或多种编程语言&#xff0c;如C#、Java、Python、C等&…

MySQL中的事务隔离级别

事务隔离级别 未提交读(Read uncommitted)是最低的隔离级别。通过名字我们就可以知道&#xff0c;在这种事务隔离级别下&#xff0c;一个事务可以读到另外一个事务未提交的数据。这种隔离级别下会存在幻读、不可重复读和脏读的问题。提交读(Read committed)也可以翻译成读已提交…

线程池与线程池参数策略

文章目录 线程池案例参数说明取值策略 线程池 使用一个线程池用于维护线程&#xff0c;可以避免频繁的进行线程创建与销毁造成的浪费。需要使用线程的时候从线程池中取出就可以了。 案例 public class ExecutorDemo {public static void main(String[] args) {int corePoolS…

Qt——HighLight篇

用HighLight绘制高亮按钮&#xff0c;之前有一篇讲述绘制pushButton按钮颜色的QpushButton绘制圆角矩形并绘制背景颜色-CSDN博客&#xff0c;这个是扩展&#xff0c;另一种实现方案。 想要将按钮的背景颜色设置为 Qt 的高亮显示颜色。可以使用 QPalette::Highlight 来获取 Qt 的…

PyCharm安装教程(超详细图文教程)

一、下载和安装 1.进入PyCharm官方下载&#xff0c;官网下载地址&#xff1a; https://www.jetbrains.com/pycharm/download/ 专业版安装插件放网盘了&#xff0c;网盘下载即可&#xff1a;itcxy.xyz/229.html2.安装 1.下载后找到PyCharm安装包&#xff0c;然后双击双击.ex…

es使用遇到的bug总结

本来版本7.4.0不行&#xff0c;最后换了个版本7.15.1就可以了&#xff0c;但又出现以下问题了&#xff1a; Beanpublic ElasticsearchClient elasticsearchClient() { // RestClient client RestClient.builder(new HttpHost("localhost", 9200,"http&q…

Paddle 基于ANN(全连接神经网络)的GAN(生成对抗网络)实现

什么是GAN GAN是生成对抗网络&#xff0c;将会根据一个随机向量&#xff0c;实现数据的生成&#xff08;如生成手写数字、生成文本等&#xff09;。 GAN的训练过程中&#xff0c;需要有一个生成器G和一个鉴别器D. 生成器用于生成数据&#xff0c;鉴定器用于鉴定数据的准确性&…