跳转至

25 - 激光雷达点云与波形

本章模拟机载(无人机)和地基激光雷达,得到离散点云和完整波形。

模拟内容

  1. 根据扫描仪参数和平台轨迹,计算每个激光脉冲的发射位置和方向;
  2. 在三角网格上计算交点,在统计植被内计算激光穿过的路径;
  3. 考虑脉冲宽度、光束发散、体散射、路径衰减和多次回波;
  4. 输出点云,也可以保留每个脉冲的完整波形。

激光雷达直接使用场景中已有的几何和光学属性。统计树冠的回波来自激光路径上连续分布的叶片后向散射。单站激光雷达的发射和接收路径相同,回波计算考虑了这一点,因此不需要额外设置热点参数。三角网格和统计植被可以出现在同一个场景中。

激光雷达的组成

一次激光雷达观测由扫描仪、平台和航线(或测站)组成:

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 测距与波形,包含可旋转点云、波形对比和采样收敛结果。

下一步