跳转至

08 - 属性系统

几何决定物体在哪里、长什么样,属性决定它如何与辐射和环境相互作用。本章介绍属性的物理域、设置方法,以及光谱属性如何对应到传感器的波段。

属性的物理域

每个属性属于一个物理域:

物理域 描述 属性 详细介绍
光学 短波辐射的反射、透射和吸收 Lambertian、RPV、WaterSurface、Prospect、Fluspect、MeasuredSpectrum、SpectrumDB、OpticalVegetation 第 9、10、12 章
热 温度和长波发射率 ThermalProperty 第 26 章
微波 介电常数和散射体 MicrowaveSoil、MicrowaveVegetation、MicrowaveTrunk 等 第 28 章
生物物理 与空气交换感热、潜热,土壤热通量 BiophysicalProperty 第 32 章
生理 光合作用和气孔导度 Farquhar 第 33 章

一个组件可以同时具有多个物理域的属性,用 set_property() 逐个设置。LESS 根据属性类型判断它属于哪个物理域,设置新属性时只替换同一物理域原有的属性:

import less

tree = less.Object("ash", mesh=less.asset_path("FREX.obj"))

tree.set_property("leaves", less.Prospect(cab=40, car=10))                   # 光学
tree.set_property("leaves", less.ThermalProperty(temperature=303.15, emissivity=0.98))  # 热
tree.set_property("leaves", less.BiophysicalProperty(leaf_width=0.05))        # 生物物理
tree.set_property("leaves", less.Farquhar(Vcmax25=60))                        # 生理
tree.set_property("stem_branch", less.Lambertian(reflectance=0.1))

tree.set_property("leaves", less.Prospect(cab=20))   # 只替换光学属性

物体只有一个组件,或希望所有组件使用同一属性时,可以省略组件名:

maize = less.Object("maize", mesh=less.asset_path("maize.obj"))
maize.set_property(less.Prospect(cab=45))

tree.components 列出 OBJ 文件中的组件名(即 OBJ 的 group 名):

print(tree.components)   # ['leaves', 'stem_branch']

不需要为每个组件设置所有物理域的属性,只要参与当前模拟的组件具有所需的属性即可(见第 4 章的表格)。

光谱属性与波段

光学属性可以是一个数值(所有波长相同),也可以是一条光谱曲线:

soil = less.Lambertian(reflectance=0.15)

soil_spectrum = less.Lambertian(
    wavelengths=[400, 550, 670, 800, 1600],      # nm
    reflectance=[0.10, 0.14, 0.18, 0.22, 0.30],
)

模拟时,光谱曲线按传感器的实际波长线性插值。同一个属性因此可以直接用于 RGB、多光谱和高光谱传感器,不需要事先确定波段。

以 Lambertian 的数值输入为例,三种写法的含义不同:

输入 模拟时如何使用
单个数值,如 reflectance=0.15 所有模拟波长使用相同值。
数值数组,同时提供 wavelengths 按波长坐标线性插值到传感器请求的模拟波长。
数值数组,不提供 wavelengths 数组长度必须等于模拟波长数,按顺序一一对应;不会推断波长坐标或自动插值。

例如,光谱在 500、600、700 nm 的反射率分别为 0.1、0.3、0.2,传感器请求 550 nm 时,插值得到的反射率为 0.2:

soil = less.Lambertian(
    wavelengths=[500, 600, 700],
    reflectance=[0.1, 0.3, 0.2],
)
print(soil.evaluate([550])["reflectance"])   # [0.2]

只有一个元素的数值数组也按常数处理。需要在不同传感器之间复用多点数组光谱时,应提供 wavelengths。插值只是在已有光谱采样点之间估计数值,不能恢复原始数据中未被采到的窄吸收特征。

有效波长范围

“可以指定任意波长”不等于所有波长都有可靠的物性数据。应让全部模拟波长落在属性数据及所用物理模型的有效范围内。当前 Lambertian 的带波长数值数组,以及 Prospect.evaluate(),在范围外使用最近的端点值;这不是有物理依据的范围外预测。其他属性可能直接拒绝范围外请求,不应把端点延伸视为通用规则。

PROSPECT 等叶片模型直接由生化参数计算 400–2500 nm 的光谱。可以用 evaluate() 查看属性在给定波长上的值:

leaf = less.Prospect(cab=40, car=10)
values = leaf.evaluate([450, 550, 650, 850])
print(values["reflectance"], values["transmittance"])

离散波长与宽波段

传感器设置 bands=[550, 850] 时,计算的是 550 nm 和 850 nm 两个离散波长,不是以它们为中心的宽波段平均值。Hyperspectral 同样生成一组离散模拟波长,其 step 是波长采样间隔,不代表仪器的光谱响应宽度。

模拟真实仪器的宽波段响应时,应使用 SRFBands 或相应的传感器波段定义。LESS 在光谱响应函数(SRF)覆盖的范围内生成模拟波长,将属性光谱插值到这些波长,逐波长模拟后再对结果按 SRF 加权积分;不是先平均反射率再只模拟中心波长。此时,物性光谱应覆盖整个 SRF 范围,而不仅是中心波长。

spectral_resolution 控制 SRF 积分使用的波长采样间隔(nm)。定量分析时逐步减小该间隔,检查结果是否稳定;增加光子采样数不能补偿光谱采样过粗造成的误差。传感器设置示例见第 18 章和第 19 章。

反射率与透射率之和不能超过 1,否则在创建属性时报错。

修改场景中的属性

属性可以随时修改,下一次模拟会使用新的属性,不需要重建几何:

scene = less.Scene()
scene.size = 20.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())
handle = scene.add(tree, positions=[[5, 5, 0], [10, 10, 0], [15, 15, 0]])

sensor = less.OpticalImager(less.Orthographic(image_size=64),
                            bands=[650, 550, 450], quality=16)
summer = scene.simulate(sensor)

tree.set_property("leaves", less.Prospect(cab=8, car=12, cbrown=0.3))
scene.terrain.set_property(less.Lambertian(reflectance=0.25))
autumn = scene.simulate(sensor)

也可以用“物体名.组件名”的路径直接修改:

scene.update_property("ash.leaves", less.Prospect(cab=40))

为单个实例设置属性

同一物体的所有实例默认共享属性。scene.add() 返回的句柄可以为指定实例替换某个组件的属性,其他实例保持不变:

# 每个实例一个属性,None 表示沿用物体的属性
handle.set_property("leaves", [None,
                               less.Prospect(cab=20),
                               less.Prospect(cab=10, cbrown=0.2)])

# 用实例编号选择
handle.set_property("stem_branch", less.Lambertian(reflectance=0.2), instances=[0, 2])

# 用函数按实例编号生成
handle.set_property("leaves", lambda i: less.Prospect(cab=20 + 10 * i))

# 恢复为物体的属性
handle.clear_property("leaves", "optical")

mixed = scene.simulate(sensor)

逐实例属性适用于三角网格组件;统计植被组件每个组件使用一个属性。

内置光谱库

LESS 自带一组实测光谱,覆盖常见的叶片、土壤和人工材料:

library = less.SpectrumLibrary()
names = library.list_spectra()
print(len(names), names[:5])

data = library.get("birch_leaf_green")
print(data["wavelength"][:3], data["reflectance"][:3])

scene.terrain.set_property(less.SpectrumDB("loam_brown"))

less.SpectrumDB(name) 直接把光谱库中的一条光谱作为光学属性。

下一步