05 - 第一次模拟:裸地 RGB 图像¶
本章将用最少的代码完成您的第一次辐射传输模拟。我们将创建一个简单的裸地场景,生成一张 RGB 图像。
模拟原理¶
在最简单的情况下,场景只有一块平坦的地面。太阳光照射地面,地面反射的辐亮度被正射传感器接收,形成图像。
正射投影成像¶
正射投影(Orthographic)传感器从正上方向下观测场景。所有的观测光线互相平行——就像卫星从极高的高度观测地面一样。
关键参数的含义:
image_size:图像的像素数(例如 256 表示 256×256 像素)extent:地面成像范围(米),默认等于scene.sizeresolution:地面分辨率(米/像素),与image_size二选一center:成像中心点,默认为场景中心
extent = image_size × resolution。如果场景 50m,image_size=500,则 resolution = 0.1 m/pixel。
RGB 波段¶
要生成 RGB 图像,我们需要指定红、绿、蓝三个波段的中心波长。LESS 中,波段按列表给出的顺序排列:
完整代码¶
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("模拟完成!")
代码解读¶
Scene 和 Terrain¶
less.Scene() 创建一个空场景。scene.size = 10.0 设定场景地面范围为 10m × 10m。
less.Terrain() 创建地表。Lambertian(reflectance=0.3) 是最简单的光学属性——朗伯体,即各方向反射率相同。reflectance=0.3 表示反射 30% 的入射光。
SimpleSpectralAtmosphere 光照模型¶
Illumination(Sun, SimpleSpectralAtmosphere) 包含两个分量:
- 直射太阳光:由
sun_zenith(天顶角)和sun_azimuth(方位角)确定方向 - 漫射天空光:基于简化光谱大气模型(Rayleigh + 气溶胶 + 臭氧 + 水汽)自动计算,各方向近似均匀
真空条件使用
NoAtmosphere();已知 TOA 到地表的传输系数时使用PrescribedAtmosphere。Sun.irradiance始终是 TOA 束法向光谱辐照度。
simulate()¶
scene.simulate(sensor) 会在第一次调用时自动准备场景和构建加速结构,然后执行蒙特卡洛光线追踪并返回结果。普通模拟不需要提前调用 scene.build();需要强制刷新外部修改的几何文件时使用 scene.rebuild()。详见场景生命周期。
quality 参数¶
quality 控制每个像素发射的光子数量。值越大,图像噪声越低,但计算时间越长。
| quality | 噪声水平 | 适用场景 |
|---|---|---|
| 16-64 | 明显噪声 | 快速预览、教程演示 |
| 128-256 | 较低噪声 | 一般分析 |
| 512-2048 | 噪声可忽略 | 发表质量 |
输出产品¶
保存为图像¶
访问原始数据¶
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.Scene、less.Terrain、less.Objectless.Lambertian、less.Prospectless.Illumination、less.Sun、less.SimpleSpectralAtmosphereless.Orthographic、less.OpticalImagerless.Product.save()、less.Product.to_brf()