25 - 激光雷达点云与波形¶
本章模拟机载(无人机)和地基激光雷达,得到离散点云和完整波形。
模拟内容¶
- 根据扫描仪参数和平台轨迹,计算每个激光脉冲的发射位置和方向;
- 在三角网格上计算交点,在统计植被内计算激光穿过的路径;
- 考虑脉冲宽度、光束发散、体散射、路径衰减和多次回波;
- 输出点云,也可以保留每个脉冲的完整波形。
激光雷达直接使用场景中已有的几何和光学属性。统计树冠的回波来自激光路径上连续分布的叶片后向散射。单站激光雷达的发射和接收路径相同,回波计算考虑了这一点,因此不需要额外设置热点参数。三角网格和统计植被可以出现在同一个场景中。
激光雷达的组成¶
一次激光雷达观测由扫描仪、平台和航线(或测站)组成:
import less
scanner = less.Scanner(
beam_divergence=0.5, # 光束发散角(mrad)
pulse_rate=20_000, # 脉冲频率(Hz)
scan_freq=80.0, # 扫描频率(Hz)
scan_angle=27.0, # 半扫描角(度)
wavelengths=[1064], # 激光波长(nm)
beam_samples=4, # 每个光束内的采样数,用于表示光斑大小
)
| 参数 | 含义 | 机载典型值 | 地基典型值 |
|---|---|---|---|
beam_divergence |
光束发散角(mrad) | 0.3–0.5 | 0.1–0.3 |
pulse_rate |
脉冲频率(Hz) | 10⁵–4×10⁵ | — |
scan_freq |
扫描频率(Hz) | 50–200 | — |
scan_angle |
半扫描角(度) | 15–30 | — |
wavelengths |
波长(nm) | 1064 | 1550 |
beam_samples |
光束采样数 | 4–16 | 1–4 |
angular_resolution |
地基扫描的角分辨率(度) | — | 0.05–0.2 |
max_returns |
每个脉冲最多的回波数 | — | — |
平台:
uav = less.UAV(altitude=50.0, speed=5.0)
aircraft = less.Aircraft(altitude=1000.0, speed=60.0)
tripod = less.Tripod(height=1.5)
vehicle = less.Vehicle(height=2.5, speed=5.0)
机载用航点定义航线,地基用测站定义扫描范围:
flight_line = [less.Waypoint(-10, 25, active=True), less.Waypoint(60, 25, active=True)]
station = [less.ScanPosition(x=25, y=25, azimuth_range=(0, 360), zenith_range=(5, 80))]
无人机激光雷达¶
scene = less.Scene()
scene.size = 50.0
scene.terrain = less.Terrain(property=less.Lambertian(reflectance=0.15))
scene.illumination = less.Illumination(
source=less.Sun(zenith=30, azimuth=150), atmosphere=less.NoAtmosphere())
tree = less.Object("ash", mesh=less.asset_path("FREX.obj"))
tree.set_property("leaves", less.Prospect(cab=40, car=10, cw=0.012, cm=0.008, N=1.5))
tree.set_property("stem_branch", less.Lambertian(reflectance=0.08))
positions = less.place.random(scene, n=60, min_dist=3.0, seed=42)
n = len(positions)
scene.add(tree, positions=positions,
scales=less.place.uniform_scale(n, 0.6, 1.5, seed=42),
rotations=less.place.random_rotation(n, seed=42))
als = less.LiDARSurvey(
scanner=scanner,
platform=uav,
legs=flight_line,
range_resolution=0.15, # 距离分辨率(m)
name="UAV LiDAR",
)
cloud = scene.simulate(als)
cloud.save("uav_pointcloud.ply")
print(cloud.num_points, "个点")
print("高度范围:", cloud.points[:, 2].min(), "~", cloud.points[:, 2].max(), "m")
地基激光雷达¶
地基激光雷达从固定测站做半球扫描,近处点密度很高:
tls = less.LiDARSurvey(
scanner=less.Scanner(beam_divergence=0.2, wavelengths=[1550], beam_samples=1,
angular_resolution=0.5), # 角分辨率 0.5°
platform=tripod,
legs=station,
range_resolution=0.02,
name="TLS",
)
tls_cloud = scene.simulate(tls)
tls_cloud.save("tls_pointcloud.ply")
| 机载 | 地基 | |
|---|---|---|
| 视角 | 自上而下 | 自下而上、水平 |
| 范围 | 航线覆盖的大片区域 | 测站周围 |
| 点密度 | 每平方米 1–20 点 | 每平方米 100 点以上 |
| 擅长 | 冠层高度、大面积制图 | 树干、冠层内部结构 |
点云内容¶
print(cloud.points.shape) # (点数, 3)坐标
print(cloud.intensity.shape) # 强度
print(cloud.return_number[:10]) # 回波序号
print(cloud.num_returns[:10]) # 所在脉冲的回波总数
离散回波从每个脉冲的波形中提取:保留最强的若干个峰(不超过 Scanner.max_returns),再按距离从近到远编号;强度是各波长通道之和。cloud.return_timeline 给出脉冲发射和回波到达的时间范围。
完整波形¶
waveform_product = scene.simulate(als, product="waveform")
waveform = waveform_product.waveform["data"]
print(waveform.shape) # (脉冲, 距离单元, 波长)
print(waveform_product.waveform["min_range"]) # 第一个距离单元的起点(m)
print(waveform_product.waveform["range_resolution"]) # 距离单元的长度(m)
点云和波形来自同一次传播计算,点云中树冠、林下和地面的回波与波形一致。
多条航线¶
strips = []
for y in (15, 25, 35):
strips += [less.Waypoint(-10, y, active=True), less.Waypoint(60, y, active=True)]
multi_strip = less.LiDARSurvey(
scanner=less.Scanner(beam_divergence=0.5, pulse_rate=20_000, scan_freq=80.0,
scan_angle=20.0, wavelengths=[1064], beam_samples=4),
platform=uav, legs=strips, range_resolution=0.15, name="Multi-strip")
常见应用¶
| 应用 | 数据 | 方法 |
|---|---|---|
| 冠层高度模型 | 机载点云 | 最高点减地面高程 |
| 叶面积指数 | 机载点云 | 间隙率法 |
| 单木分割 | 机载或地基 | 分水岭、深度学习 |
| 胸径 | 地基 | 圆拟合 |
从点云重建场景见第 17 章。
配套脚本:scripts/25_lidar.py
无发散与有限光束的独立验证见 A5 - LiDAR 测距与波形,包含可旋转点云、波形对比和采样收敛结果。