前言
激光雷达(LiDAR, Light Detection and Ranging)技术近年来在林业、生态、测绘等多个领域中展现出强大的数据获取能力。它能够快速、精确、非接触地获取目标地物的三维空间结构,特别适用于森林这种具有复杂垂直结构的生态系统。
通过激光雷达点云数据,可以提取出诸如单木高度、胸径估测、树冠宽度、林冠层结构、地形起伏、植被间隙率等重要参数,这些数据为森林资源调查、经营规划、生态监测等工作提供了坚实的数据支撑。
因此,作为林业工作者,**掌握激光雷达点云的基本结构与处理流程还是蛮重要的。本文将从.las格式文件的结构入手,介绍其基本组成和关键字段,并展示如何使用Python进行点云数据的读取与显示。
.las格式点云数据
.las 是激光雷达点云最通用的数据交换格式,由 ASPRS(美国摄影测量与遥感学会)制定,旨在为激光雷达行业提供一种标准化的、高效的数据格式。.las 文件采用二进制格式,具备结构清晰、体积小、读取高效等特点,已成为点云数据处理工作中的行业标准格式。
LAS 文件主要由两部分组成:
-
文件头(Header):记录整体数据的基本信息,如点数、坐标范围、版本号、点格式编号等。
- 头文件信息中需要注意的就是scale(缩放)和offset(平移),在las文件中,为了压缩数据体积和提高效率,每个点的
X、Y、Z坐标都不是以浮点数直接存储,而是以整数存储,再结合头文件中提供的scale和offset来计算出点的真实地理坐标。不过 laspy 已经在自动应用了转换,所以你通常直接用las.x就是转换后的结果。如下代码的两种形式打印出来的是相同的结果:
- 头文件信息中需要注意的就是scale(缩放)和offset(平移),在las文件中,为了压缩数据体积和提高效率,每个点的
x_real5 = las.X[5] * las.header.x_scale + las.header.x_offset
print("point5:",x_real5)
print(las.x[5])
- 点数据记录(Point Records):记录每一个点的三维坐标和属性信息,如强度、分类、回波信息、颜色等。
点数据记录的主要字段说明:
| 字段名称 | 含义 | 数据类型 | 长度 |
|---|---|---|---|
| X | 点的 X 坐标(需缩放/平移) | long | 4 bytes |
| Y | 点的 Y 坐标(需缩放/平移) | long | 4 bytes |
| Z | 点的 Z 坐标(需缩放/平移) | long | 4 bytes |
| intensity | 激光回波的强度值 | unsigned short | 2 bytes |
| return_number | 当前点是该激光脉冲的第几次回波 | 3 bits | 3位 |
| number_of_returns | 该激光脉冲总共检测到几次回波 | 3 bits | 3位 |
| classification | 点的类别(如地面、植被、建筑等) | unsigned char | 1 byt |
| red | 红色通道值(颜色信息) | unsigned short | 2 bytes |
| green | 绿色通道值(颜色信息) | unsigned short | 2 bytes |
| blue | 蓝色通道值(颜色信息) | unsigned short | 2 bytes |
说明:不同的 LAS 点格式(如 Format 0, 1, 2, 3...)包含的字段有所不同。颜色信息(RGB)一般从 Format 2 开始支持。
点云数据读取与显示
- 调用laspy对点云数据进行读取,先查看其头文件信息
'''
@微信公众号:生态遥感学习记录
'''
import laspy
import pyvista as pv
import numpy as np
# 1.读取文件
las = laspy.read(r"C:\Users\YSYmc\Desktop\近期内容\lidar_data\test.las")
# 2.打印基本属性信息
print("点云总点数:", las.header.point_count)
print("LAS版本:", las.header.version)
print("点格式:", las.header.point_format)
print("x_offset:",las.header.x_offset)
print("x_scale:",las.header.x_scale)
print("点云范围:")
print(f" X: {las.x.min():.2f} - {las.x.max():.2f}")
print(f" Y: {las.y.min():.2f} - {las.y.max():.2f}")
print(f" Z: {las.z.min():.2f} - {las.z.max():.2f}")
print("包含的属性字段",list(las.point_format.dimension_names))
- 查看点数据属性信息:
#3.打印点的属性信息(前五个点)
print("\n前 5 个点的详细属性:")
for i in range(5):
info = f"Point {i+1}: x={las.x[i]:.2f}, y={las.y[i]:.2f}, z={las.z[i]:.2f}"
if "intensity" in las.point_format.dimension_names:
info += f", intensity={las.intensity[i]}"
if "return_number" in las.point_format.dimension_names:
info += f", return_num={las.return_number[i]}"
if "number_of_returns" in las.point_format.dimension_names:
info += f", num_returns={las.number_of_returns[i]}"
if "classification" in las.point_format.dimension_names:
info += f", class={las.classification[i]}"
print(info)
- 按属性字段显示点云数据,为了流畅查看我对点云数据进行了抽稀
#4.随机抽稀点云(保留70%),这是为了不卡顿,方便挪动查看
keep_ratio = 0.7
total = len(las.x)
indices = np.random.choice(total, int(total * keep_ratio), replace=False)
#重构点云数据将其转为每一行为每一个点的x、y、z数据
points = np.vstack((las.x[indices], las.y[indices], las.z[indices])).T
cloud = pv.PolyData(points)
cloud["Elevation"]=las.z[indices]
color_field = "Elevation" # 你可以改成其他字段
#5.可视化点云
cloud.plot(
scalars=color_field #基于该属性字段进行着色
,cmap="viridis" # 其他的色带:'viridis', 'plasma', 'terrain', 'coolwarm'
,point_size=2 #控制点的显示大小
,show_scalar_bar=True #显示colorbar
,render_points_as_spheres=True)#该参数用于控制点云在渲染时是否以球体的形式显示,是的话显示效果更好

4.按RGB显示点云数据,该点云数据已经使用了照片进行了点云附色
r = las.red[indices]
g = las.green[indices]
b = las.blue[indices]
rgb = np.column_stack((r, g, b)) # shape = (N, 3)
# 5. 按RGB显示点云
cloud.point_data['RGB'] = rgb
cloud.plot(rgb=True, point_size=2, render_points_as_spheres=True)
#rgb=True,表示使用RGB附点云颜色
