Automated atmospheric correction

multispectral
preprocessing
A Python module, built for a satellite imagery provider, that corrects each new multispectral image to surface reflectance with no manual inputs, using the 6S model with aerosol and elevation drawn from the image’s own spatial footprint and date.

A Python module, built for a satellite imagery provider, that corrects each new multispectral image to surface reflectance with no manual inputs, using the 6S model with aerosol and elevation drawn from the image’s own spatial footprint and date.

Employer: Sparkgeo (client project)
When: 2023
Data: Commercial multispectral satellite imagery, MODIS Terra and Aqua monthly aerosol optical depth (MOD08_M3, MYD08_M3), NASADEM
Methods: Radiometric calibration, top-of-atmosphere reflectance, 6S radiative transfer model, monthly aerosol climatology, scene-average aerosol and elevation inputs, comparison with Sentinel-2 L2A
Stack: Python, Py6S, Docker, AWS (S3), Cloud Optimized GeoTIFF (COG)

Background

Satellites record light that has passed through the atmosphere twice, so the values in a raw image mix the surface with haze, aerosols and scattering. Atmospheric correction removes those effects to give bottom-of-atmosphere (surface) reflectance, which can be compared across dates and sensors. It needs inputs that don’t come with the image, such as how much aerosol was in the air and how high the ground is. Our client, a satellite imagery provider, didn’t offer atmospheric correction in its processing pipeline at the time, and needed a tool that could run automatically on each new image.

My contribution

I designed and built the module.

  • Object-oriented design: an image and its metadata are loaded into a single object. Each correction stage is a method that pulls the metadata it needs, and the stages run in series: radiometric calibration to top-of-atmosphere (TOA) radiance, conversion to TOA reflectance, then correction to bottom-of-atmosphere (BOA) reflectance.
  • Built to extend: a generic sensor base class is adapted for each sensor. The first implementation supported the client’s imagery; another sensor could be added by writing a new sensor class.
  • Radiative transfer: the BOA correction uses the 6S atmospheric model through Py6S.
  • Aerosol input: I built a monthly aerosol climatology from 20 years of MODIS monthly aerosol optical depth (AOD), from the Terra and Aqua products (MOD08_M3 and MYD08_M3): one composite per calendar month, stored as COGs in S3. For each new image, the module reads the composite for the month the image was taken, averages it over the image footprint, and uses the result as the 6S AOD parameter.
  • Elevation input: in the same way, terrain elevation is read from NASADEM (a global terrain elevation dataset) over the image footprint and averaged.
  • Packaging: the whole process runs in a Docker container, driven by CLI commands.

Outcome

  • Delivered to the client: the module turns an incoming image into surface reflectance with no manual inputs, since the aerosol and elevation values come from the image’s own footprint and acquisition month.
  • Corrected images compared favourably with Sentinel-2 L2A surface reflectance from near-contemporary dates, allowing for the spectral and radiometric differences between Sentinel-2 and the client’s sensor.
  • Limitations: the aerosol input is a long-term monthly average rather than the conditions on the day, and the products’ 1° grid cells are far larger than a scene, so it can’t capture local aerosol differences. A single aerosol and elevation value is used for the whole scene, so hazy days and hilly scenes are corrected less accurately.

What I’d change now

  • Most differences between sensors are data rather than behaviour (band wavelengths, gains, solar irradiance), so I’d move them into configuration and subclass only where behaviour truly differs, such as parsing each vendor’s metadata. Adding a sensor would then mostly mean adding a config file.
  • Daily aerosol data rather than the monthly composite, ideally with spatial differentiation across the scene (i.e. not a single value for the entire scene).
  • Elevation across the scene rather than a single value, to account for within-scene topographic variations.

Cover image: Atmospheric haze sweeps over the Mediterranean. Image captured from the External High-Definition Camera (EHDC) on board the International Space Station (ISS) on April 30, 2025. Image source.