跳转至

05 - 第一次模拟:裸地 RGB 图像

本章将用最少的代码完成您的第一次辐射传输模拟。我们将创建一个简单的裸地场景,生成一张 RGB 图像。

模拟原理

在最简单的情况下,场景只有一块平坦的地面。太阳光照射地面,地面反射的辐亮度被正射传感器接收,形成图像。

正射投影成像

正射投影(Orthographic)传感器从正上方向下观测场景。所有的观测光线互相平行——就像卫星从极高的高度观测地面一样。

正射投影

关键参数的含义:

  • image_size:图像的像素数(例如 256 表示 256×256 像素)
  • extent:地面成像范围(米),默认等于 scene.size
  • resolution:地面分辨率(米/像素),与 image_size 二选一
  • center:成像中心点,默认为场景中心

extent = image_size × resolution。如果场景 50m,image_size=500,则 resolution = 0.1 m/pixel。

RGB 波段

要生成 RGB 图像,我们需要指定红、绿、蓝三个波段的中心波长。LESS 中,波段按列表给出的顺序排列:

bands = [650, 550, 450]  # 第1波段=红(650nm), 第2波段=绿(550nm), 第3波段=蓝(450nm)

完整代码

import less

# 1. 创建场景
scene = less.Scene()
scene.size = 10.0                         # 10m × 10m 场景

# 2. 设置地面属性
#    Lambertian 朗伯体:所有方向均匀反射
#    reflectance=0.3 表示反射 30% 的入射光
scene.terrain = less.Terrain(
    property=less.Lambertian(reflectance=0.3)
)

# 3. 设置光照
#    sun_zenith=30: 太阳高度角 60°
#    sun_azimuth=150: 太阳位于东南方向
scene.illumination = less.Illumination(source=less.Sun(zenith=30, azimuth=150), atmosphere=less.SimpleSpectralAtmosphere(turbidity=2.0))

# 4. 配置传感器并模拟(第一次调用会自动构建场景)
sensor = less.OpticalImager(
    less.Orthographic(image_size=256),     # 256×256 像素
    bands=[650, 550, 450],                 # R, G, B
    quality=64,                            # 光子数(教程用低值加快速度)
)
image = scene.simulate(sensor)

# 5. 保存结果
image.save("bare_soil_rgb.png")
print("模拟完成!")

配套脚本:scripts/05_first_simulation.py

代码解读

Scene 和 Terrain

less.Scene() 创建一个空场景。scene.size = 10.0 设定场景地面范围为 10m × 10m。

less.Terrain() 创建地表。Lambertian(reflectance=0.3) 是最简单的光学属性——朗伯体,即各方向反射率相同。reflectance=0.3 表示反射 30% 的入射光。

SimpleSpectralAtmosphere 光照模型

Illumination(Sun, SimpleSpectralAtmosphere) 包含两个分量:

  1. 直射太阳光:由 sun_zenith(天顶角)和 sun_azimuth(方位角)确定方向
  2. 漫射天空光:基于简化光谱大气模型(Rayleigh + 气溶胶 + 臭氧 + 水汽)自动计算,各方向近似均匀

真空条件使用 NoAtmosphere();已知 TOA 到地表的传输系数时使用 PrescribedAtmosphereSun.irradiance 始终是 TOA 束法向光谱辐照度。

simulate()

scene.simulate(sensor) 会在第一次调用时自动准备场景和构建加速结构,然后执行蒙特卡洛光线追踪并返回结果。普通模拟不需要提前调用 scene.build();需要强制刷新外部修改的几何文件时使用 scene.rebuild()。详见场景生命周期

quality 参数

quality 控制每个像素发射的光子数量。值越大,图像噪声越低,但计算时间越长。

quality 噪声水平 适用场景
16-64 明显噪声 快速预览、教程演示
128-256 较低噪声 一般分析
512-2048 噪声可忽略 发表质量

输出产品

保存为图像

image.save("output.png")     # PNG(自动色调映射为 8-bit)
image.save("output.tif")     # GeoTIFF(保留原始物理量)

访问原始数据

import numpy as np

data = image.data
print(f"数据形状: {data.shape}")    # (256, 256, 3)
print(f"数据类型: {data.dtype}")    # float32
print(f"数据范围: {data.min():.4f} ~ {data.max():.4f}")

返回的是辐亮度值(W/m²/sr/nm),而不是 0-255 的像素值。这是原始的物理量,可以用于定量分析。

尝试修改参数

得益于数字孪生架构,您可以直接修改参数并重新模拟,无需重新 build

# 改变太阳位置
scene.illumination = less.Illumination(source=less.Sun(zenith=60, azimuth=90), atmosphere=less.SimpleSpectralAtmosphere(turbidity=2.0))
image2 = scene.simulate(sensor)
image2.save("bare_soil_low_sun.png")

# 改变地面反射率
scene.terrain.set_property(less.Lambertian(reflectance=0.1))
image3 = scene.simulate(sensor)
image3.save("bare_soil_dark.png")

添加一棵植物

让我们在裸地上添加一棵玉米,看看效果:

# 加载内置的玉米模型
maize = less.Object("maize", mesh=less.examples.asset_path("maize.obj"))
maize.set_property(less.Prospect(cab=40, car=8, cw=0.012, cm=0.006, N=1.5))

# 在场景中心放置一棵
scene.add(maize, positions=[[5.0, 5.0, 0.0]])
scene.rebuild()  # 几何变化需要 rebuild

image4 = scene.simulate(sensor)
image4.save("one_maize.png")

在下一章中,我们将更详细地介绍地形和光学属性的配置。

下一步

相关 API

  • less.Sceneless.Terrainless.Object
  • less.Lambertianless.Prospect
  • less.Illuminationless.Sunless.SimpleSpectralAtmosphere
  • less.Orthographicless.OpticalImager
  • less.Product.save()less.Product.to_brf()