04 - How LESS works¶
This chapter gives an overview of LESS: what a scene is made of, how properties are assigned, and how one scene produces many kinds of results. The details follow in later chapters.
One scene, many simulations¶
import less
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))
tree.set_property("stem_branch", less.Lambertian(reflectance=0.1))
scene.add(tree, positions=[[25, 25, 0]])
rgb = scene.simulate(less.OpticalImager(
less.Orthographic(image_size=128), bands=[650, 550, 450], quality=32))
nir = scene.simulate(less.OpticalImager(
less.Orthographic(image_size=128), bands=[850], quality=32))
The scene is defined once. The two calls to simulate() use different sensors, and the second one reuses the geometry that is already built.
What a scene contains¶
| Part | How to set it | Meaning |
|---|---|---|
| Extent | scene.size |
Horizontal size of the ground (m) |
| Terrain | scene.terrain = less.Terrain(...) |
Flat ground, a raster elevation model or a triangle-mesh terrain |
| Objects | scene.add(less.Object(...), positions=...) |
Trees, crops, buildings …, each placed any number of times |
| Illumination | scene.illumination = less.Illumination(...) |
Sun and atmosphere |
An Object consists of one or more components. A component's geometry is represented in one of two ways:
- Triangle mesh (
less.Mesh): every triangle of the model is kept; suitable for leaves, branches and buildings (chapter 11); - Statistical vegetation (
less.TurbidBoundary): only the closed outline of the canopy is given and the leaves inside are described by leaf area density and leaf angle distribution (chapter 12).
Both kinds can appear in the same object, for example a statistical crown on a mesh trunk.
Properties¶
A property describes how a component behaves in one kind of physical process. Properties are grouped into domains:
| Domain | Role | Common properties |
|---|---|---|
| Optical | Shortwave reflection, transmission and absorption | Lambertian, Prospect, Fluspect, OpticalVegetation |
| Thermal | Temperature and emissivity | ThermalProperty |
| Microwave | Dielectric and scattering behaviour | MicrowaveSoil, MicrowaveVegetation |
| Biophysical | Exchange of sensible heat, latent heat and soil heat | BiophysicalProperty |
| Physiological | Photosynthesis and stomatal conductance | Farquhar |
A component can carry properties from several domains; each call to set_property() replaces only the property of the same domain. Properties are covered in full in Properties.
Sensors and processes¶
scene.simulate() accepts two kinds of objects:
- Sensors observe the scene from somewhere in some way and return images, point clouds, waveforms and other observations;
- Processes solve for a physical state in the scene, such as the radiation absorbed by each leaf, the leaf temperature or the photosynthetic rate.
| Kind | Object | Result | Chapters |
|---|---|---|---|
| Optical sensors | OpticalImager, BRFSensor |
Images, multi-angle reflectance | 19–22 |
| Radiation measurements | IrradianceMapSensor, IrradianceRadiometer |
Irradiance maps, irradiance | 23–24 |
| LiDAR | LiDARSurvey |
Point clouds, waveforms | 25 |
| Thermal | ThermalImager |
Thermal images | 26 |
| Fluorescence | SIFImager |
Fluorescence images | 27 |
| Microwave | RadarScatterometer, MicrowaveRadiometer |
Backscattering coefficients, brightness temperatures | 28–30 |
| Processes | RadiationFieldProcess, EnergyBalanceProcess, PhotosynthesisProcess |
Radiation field, leaf temperature, photosynthesis | 31–33 |
Results of processes feed into sensors. For example, leaf temperatures from the energy balance are used directly by thermal imaging, and the fluorescence computed with photosynthesis is used by fluorescence imaging.
Which properties each simulation needs¶
"Needed" refers only to the components that take part in the simulation.
| Simulation | Optical | Thermal | Microwave | Biophysical | Physiological |
|---|---|---|---|---|---|
| Optical imaging, multi-angle reflectance | needed | — | — | — | — |
| LiDAR | needed | — | — | — | — |
| Radiation field | needed | — | — | — | — |
| Thermal imaging (prescribed temperature) | — | needed | — | — | — |
| Energy balance | needed | needed | — | needed | optional |
| Photosynthesis (prescribed leaf temperature) | needed | needed | — | — | needed |
| Photosynthesis (with leaf temperature) | needed | needed | — | needed | needed |
| Fluorescence (fixed quantum yield) | Fluspect |
— | — | — | — |
| Fluorescence (following photosynthesis) | Fluspect |
needed | — | needed | needed |
| Radar, passive microwave | — | optional | needed | — | — |
If a required property is missing, LESS stops before the simulation starts and tells you which component lacks which kind of property.
Scene lifecycle¶
Usually you only call simulate(): the first call builds the scene, later calls reuse the geometry and acceleration structures.
| Method | What it does | When to use it |
|---|---|---|
scene.simulate(...) |
Builds if necessary, then simulates | Everyday use |
scene.build() |
Builds ahead of time; does nothing if the scene has not changed | Timing the build separately; before updating instances |
scene.rebuild() |
Re-reads all geometry and rebuilds unconditionally | An OBJ or DEM file at the same path was changed outside LESS |
Changing the illumination, properties or sensors needs no rebuild:
scene.illumination = less.Illumination(
source=less.Sun(zenith=50, azimuth=200), atmosphere=less.NoAtmosphere())
tree.set_property("leaves", less.Prospect(cab=20))
rgb_autumn = scene.simulate(less.OpticalImager(
less.Orthographic(image_size=128), bands=[650, 550, 450], quality=32))
When the geometry changes through scene.add(), scene.terrain = ... and similar calls, the next simulate() rebuilds automatically.
Results¶
simulate() returns a result object. Common operations:
print(rgb.data.shape) # NumPy array: (rows, columns, bands)
rgb.save("forest_rgb.png") # save as a picture
rgb.save("forest_rgb.tif") # save the values
brf = rgb.to_brf() # radiance to reflectance factor
| Simulated with | Result | Main content |
|---|---|---|
OpticalImager |
Image | Radiance per band, convertible to reflectance factor |
ThermalImager |
Image | Thermal radiance, convertible to brightness temperature |
BRFSensor |
Multi-angle reflectance | Reflectance factor per direction and band |
LiDARSurvey |
Point cloud or waveform | Coordinates, intensity, return numbers or waveforms |
EnergyBalanceProcess |
Energy balance | Temperature, net radiation, sensible and latent heat |