跳转至

12 - 热红外模拟

本章介绍如何使用 LESS 模拟热红外遥感图像。

热红外遥感原理

所有温度高于绝对零度的物体都会发射热辐射。在热红外波段(8-14 μm),地表物体的热辐射与其 温度发射率 有关:

L = ε × B(T, λ)

其中: - L:热辐亮度 (W/m²/sr/μm) - ε:发射率 (0-1) - B(T, λ):普朗克函数(黑体辐射) - T:物体温度 (K)

植被冠层中,不同组分(阳面叶片、阴面叶片、土壤、树干)的温度不同,这导致热红外图像中存在丰富的温度空间分异信息。

ThermalProperty —— 热属性

每个场景元素都可以设置热属性,独立于光学属性:

import less

# 叶片:阳面和阴面温度不同
leaf_thermal = less.ThermalProperty(
    emissivity=0.98,
    temperature_sunlit=305.0,     # 阳面温度 (K) ≈ 32°C
    temperature_shaded=300.0,     # 阴面温度 (K) ≈ 27°C
)

# 土壤:温差更大
soil_thermal = less.ThermalProperty(
    emissivity=0.95,
    temperature_sunlit=312.0,     # 阳面 ≈ 39°C
    temperature_shaded=303.0,     # 阴面 ≈ 30°C
)

# 树干:使用单一温度
trunk_thermal = less.ThermalProperty(
    emissivity=0.97,
    temperature=300.0,            # 统一温度 ≈ 27°C
)

# 光谱发射率(插值到模拟波段)
asphalt = less.ThermalProperty(
    emissivity=[0.95, 0.97],
    wavelengths=[10600, 12000],
    temperature=320.0,
)

阳面/阴面温度

LESS 根据每个三角面片的法线方向和太阳方向的关系,自动判断该面片处于阳面还是阴面:

  • 阳面 (sunlit):面片法线朝向太阳且未被遮挡 → 使用 temperature_sunlit
  • 阴面 (shaded):法线背向太阳或被遮挡 → 使用 temperature_shaded

这比使用单一温度更加真实。

ThermalImager —— 热红外成像仪

sensor_thermal = less.ThermalImager(
    less.Orthographic(image_size=512),
    bands=[10600],        # 10.6 μm = 10600 nm(Landsat TIRS B10)
    quality=128,
)

常用热红外波段:

传感器 波段 中心波长
Landsat TIRS B10 10.6 μm 10600 nm
Landsat TIRS B11 12.0 μm 12000 nm
ASTER B13 10.7 μm 10700 nm
MODIS B31 11.0 μm 11000 nm

不设置 instrument 时,ThermalImager 输出进瞳辐亮度(W/m²/sr/nm)。需要 TOA 或指定高度的大气路径时,把 scene.illumination.atmosphere 设为 less.Atmosphere,并使用 observation_level="toa"observation_altitude_km。投影目前支持正射(Orthographic)和推扫(Pushbroom)。

scene.illumination = less.Illumination(
    source=less.Sun(zenith=30, azimuth=150),
    atmosphere=less.Atmosphere.standard("midlatitude_summer"),
)

toa = scene.simulate(less.ThermalImager(
    less.Orthographic(image_size=256),
    bands=less.gaussian_bands([("LWIR_10.6", 10600, 1000)]),
    observation_level="toa",
))

dn = scene.simulate(less.ThermalImager(
    less.Pushbroom(
        resolution=256, num_lines=256,
        altitude=5000.0, swath_width=50.0,
    ),
    bands=[10600, 12000],
    observation_level="toa",
    instrument=less.Instrument.thermal_photon(
        aperture_diameter=0.15, bandwidth=[1000, 1000],
        column_gain_sigma=0.01, seed=42,
    ),
))

Instrument.thermal_photon() 给出 MCT/QWIP 量级的量子效率、满阱、暗电流和读出噪声,不是微测辐射热计。推扫若设置了 line_rate 且未写 integration_time,积分时间为 tdi_stages / line_rateinstrument.nedt(wavelength_nm, T_ref_K, projection=...) 返回均匀黑体亮温标准差,只作诊断,不要把 NEdT_K 当作构造参数再叠一层高斯。

完整推扫例子见 examples/python/thermal_pushbroom.py

可选的 1-D 云是平面平行薄层,按像元覆盖度混合晴空柱和含云柱,不是 3D 积云:

scene.illumination = less.Illumination(
    source=less.Sun(zenith=30, azimuth=150),
    atmosphere=less.Atmosphere.standard(
        "midlatitude_summer",
        cloud=less.CloudLayer(
            cover=0.5, altitude_km=3.0, thickness_km=0.5,
            optical_depth=8.0,
        ),
        precipitable_water_g_cm2=2.1,
    ),
)

完整示例:森林热红外模拟

import less
import numpy as np

# ── 创建场景 ──────────────────────────────────────────────────
scene = less.Scene()
scene.size = 50.0

# 土壤(光学 + 热)
terrain = less.Terrain()
terrain.set_property(less.Lambertian(reflectance=0.15))
terrain.set_property(less.ThermalProperty(
    emissivity=0.95,
    temperature_sunlit=312.0,
    temperature_shaded=303.0,
))
scene.terrain = terrain

# 光照(需要设置 sky_temperature 用于长波辐射)
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))

# 热属性
tree.set_property("leaves", less.ThermalProperty(
    emissivity=0.98,
    temperature_sunlit=305.0,
    temperature_shaded=300.0,
))
tree.set_property("stem_branch", less.ThermalProperty(
    emissivity=0.97,
    temperature=300.0,
))

# 放置
rng = np.random.RandomState(42)
positions = less.place.random(scene, n=40, min_dist=4.0, seed=42)
n = len(positions)
scene.add(tree, positions=positions,
          scales=less.place.uniform_scale(n, 0.7, 1.3, seed=42),
          rotations=less.place.random_rotation(n, seed=42))
sensor_thermal = less.ThermalImager(
    less.Orthographic(image_size=512),
    bands=[10600],
    quality=128,
    name="Thermal IR",
)
image_thermal = scene.simulate(sensor_thermal)
image_thermal.save("12_thermal.png")
image_thermal.save("12_thermal.tif")    # 保留原始辐射值

# ── 同时获取 RGB 用于对比 ────────────────────────────────────
sensor_rgb = less.OpticalImager(
    less.Orthographic(image_size=512),
    bands=[650, 550, 450],
    quality=128,
)
image_rgb = scene.simulate(sensor_rgb)
image_rgb.save("12_rgb.png")

# ── 分析热图像 ───────────────────────────────────────────────
data = image_thermal.data
print(f"热辐亮度范围: {data.min():.2f} ~ {data.max():.2f} W/m²/sr/μm")

print("Tutorial 12 完成!")

配套脚本:scripts/12_thermal.py

sky_temperature 的作用

sky_temperature 定义天空在热红外波段的等效辐射温度。它影响:

  1. 天空长波辐射:天空向下的热辐射贡献
  2. 反射分量:物体表面反射的天空热辐射(尤其是低发射率表面)

典型值: - 晴天:250-270 K - 多云:270-290 K - 完全阴天:≈地面温度

温差参数的设置建议

组分 阳面温度 (K) 阴面温度 (K) 温差
阳性树叶 303-310 298-303 3-7 K
阴性树叶 300-305 297-301 2-4 K
裸土 310-320 300-308 8-15 K
草地 303-308 298-302 3-6 K
树干 单一温度 298-303 - -

这些是手动指定的温度值。如果您需要物理驱动的温度模拟,请参考 第 13 章:能量平衡

多时相热红外模拟

利用数字孪生架构,可以快速模拟不同时刻的热红外图像:

# 清晨(温差小)
terrain.set_property(less.ThermalProperty(
    emissivity=0.95, temperature_sunlit=295.0, temperature_shaded=293.0))
tree.set_property("leaves", less.ThermalProperty(
    emissivity=0.98, temperature_sunlit=294.0, temperature_shaded=293.0))
scene.illumination = less.Illumination(source=less.Sun(zenith=70, azimuth=90), atmosphere=less.NoAtmosphere())

image_morning = scene.simulate(sensor_thermal)
image_morning.save("12_thermal_morning.png")

# 正午(温差大)
terrain.set_property(less.ThermalProperty(
    emissivity=0.95, temperature_sunlit=318.0, temperature_shaded=305.0))
tree.set_property("leaves", less.ThermalProperty(
    emissivity=0.98, temperature_sunlit=308.0, temperature_shaded=301.0))
scene.illumination = less.Illumination(source=less.Sun(zenith=10, azimuth=180), atmosphere=less.NoAtmosphere())

image_noon = scene.simulate(sensor_thermal)
image_noon.save("12_thermal_noon.png")

注意:这里只修改了属性和光照,没有修改几何,所以 不需要 rebuild

下一步

Turbid 热红外

TurbidBoundary 的热成像直接消费 resident 温度状态与自适应空间场。使用 ThermalImager(mode="property") 可观察属性温度,使用 mode="eb"mode="precomputed" 可观察能量平衡结果。Python 不再生成叶片或上传逐样本温度。

相关 API

  • less.ThermalProperty
  • less.ThermalImagerless.Orthographic
  • less.Illuminationless.Sunless.Atmosphere
  • less.EnergyBalanceProcessless.Microclimate
  • less.Product.save()