Tutorial 1 — ASTER Mt. Rainier#
Reading this as a static page? To run the notebook, open this repo in a GitHub Codespace; ASP and
asp-plotcome pre-installed.
An end-to-end ASP run. A single ASTER L1A scene to a 30 m DEM, twice: first from the raw imagery, then orthorectified onto a Copernicus reference DEM, each with a diagnostic PDF report.
We chose ASTER for the first tutorial because:
The data is fully open. We use a Zenodo-hosted V003 archive; no Earthdata login.
A single L1A scene contains both the nadir-looking and back-looking views, so there’s no “finding a pair” step.
What we’ll do#
Download the L1A archive from Zenodo.
Run
aster2aspto extract the nadir and back-looking imagery and camera files.Run
parallel_stereoandpoint2demon the raw imagery for a first 30 m DEM.Generate a PDF report with
asp-plot.Clip a Copernicus DEM tile from AWS Open Data.
Re-process with orthorectification (ASP calls it “mapprojection”) onto the Copernicus DEM.
Generate a second report and compare.
Scene: ASTER L1A acquired 2017-07-31 over Mt. Rainier, WA.
Reference: ASP’s official ASTER example.
from pathlib import Path
DATA = "../data/aster_rainier"
!mkdir -p {DATA}
REF_DEM = f"{DATA}/ref/cop30_rainier.tif"
1. Download the scene#
We use the V003 archive on Zenodo (preserved for tutorials after NASA decommissioned V003 in Dec 2025). The download_aster.sh script handles fetch + unzip; if the data is already there it’s a no-op.
!bash ../scripts/download_aster.sh {DATA}
!ls -1 {DATA}/dataDir/ | head
2. Sensor prep — aster2asp#
aster2asp reads the L1A archive and writes out four files: a nadir-view image (out-Band3N.tif), a back-looking image (out-Band3B.tif), and an XML camera file for each. After this step the data is in the standard “image.tif + image.xml” pair that the rest of ASP works with.
if Path(f"{DATA}/out-Band3N.tif").exists():
print(f"{DATA}/out-Band3N.tif exists — skipping aster2asp. Delete out-Band3*.* to reprocess.")
else:
!aster2asp {DATA}/dataDir -o {DATA}/out
!ls -1 {DATA}/out-Band3*.tif {DATA}/out-Band3*.xml
3. Stereo — 30 m DEM from the raw imagery#
Run parallel_stereo directly on the raw imagery — no bundle adjustment, no orthorectification — and grid the result at 30 m.
-t asterselects the ASTER session (knows about ASTER cameras).--stereo-algorithm asp_bm: plain block matching, fast.--subpixel-mode 1: parabolic subpixel refinement, cheaper than Bayes-EM.--processes 4 --threads-multiprocess 1matches the 4-core Codespace floor. On a larger machine, bump--processesto your core count.
%%time
if Path(f"{DATA}/stereo/run-DEM.tif").exists():
print(f"{DATA}/stereo/run-DEM.tif exists — skipping stereo. Delete {DATA}/stereo/ to reprocess.")
else:
!parallel_stereo -t aster \
--stereo-algorithm asp_bm \
--subpixel-mode 1 \
--processes 4 --threads-multiprocess 1 \
{DATA}/out-Band3N.tif {DATA}/out-Band3B.tif \
{DATA}/out-Band3N.xml {DATA}/out-Band3B.xml \
{DATA}/stereo/run
!point2dem --tr 30 -r earth --auto-proj-center --errorimage {DATA}/stereo/run-PC.tif
!ls -lh {DATA}/stereo/run-DEM.tif
4. First report#
The asp-plot CLI produces a PDF report: input scenes, disparity, hillshades, and an ICESat-2 ATL06-SR comparison with pc_align alignment.
We disable --plot_geometry because ASTER doesn’t have the per-scene XML metadata that DigitalGlobe/Vantor provides for the stereo-geometry skyplot.
Expect this cell to take a few minutes; it fetches ATL06-SR data via SlideRule and runs pc_align.
%%time
if Path(f"{DATA}/stereo/rainier_aster_report.pdf").exists():
print(f"{DATA}/stereo/rainier_aster_report.pdf exists — skipping asp_plot CLI. Delete it to regenerate.")
else:
!asp_plot \
--directory {DATA} \
--stereo_directory stereo \
--plot_altimetry True \
--plot_geometry False \
--subset_km 5 \
--report_filename rainier_aster_report.pdf
The report is at: data/aster_rainier/stereo/rainier_aster_report.pdf.
5. Reference DEM from AWS Copernicus DEM#
Orthorectification needs a reference DEM. Copernicus GLO-30 is on AWS Open Data; no API key, no auth.
scene_bbox runs ASP’s camera_footprint on each view and unions the results; utm_epsg picks the UTM zone at the bbox center. fetch_cop_dem.py then clips, mosaics, and reprojects the matching COP30 tiles.
from utils import scene_bbox, utm_epsg
BBOX = scene_bbox(
(f"{DATA}/out-Band3N.tif", f"{DATA}/out-Band3N.xml"),
(f"{DATA}/out-Band3B.tif", f"{DATA}/out-Band3B.xml"),
session="aster",
)
T_SRS = utm_epsg(BBOX)
print(f"Scene bbox: {BBOX} UTM: {T_SRS}")
Path(f"{DATA}/ref").mkdir(exist_ok=True)
if Path(REF_DEM).exists():
print(f"{REF_DEM} exists — skipping COP30 fetch. Delete it to redownload.")
else:
!python ../scripts/fetch_cop_dem.py \
--bbox {BBOX} \
--t-srs {T_SRS} \
--tr 30 \
--out {REF_DEM}
!ls -lh {REF_DEM}
6. Orthorectified pass#
Run mapproject to orthorectify both images onto the Copernicus DEM at 15 m, and re-run stereo on the orthorectified pair. The matcher’s search range is much smaller because the inputs are already aligned to the terrain.
%%time
if Path(f"{DATA}/stereo_ortho/run-DEM.tif").exists():
print(f"{DATA}/stereo_ortho/run-DEM.tif exists — skipping mapprojected pass. Delete {DATA}/stereo_ortho/ to reprocess.")
else:
!mapproject --t_srs {T_SRS} --tr 15 \
{REF_DEM} \
{DATA}/out-Band3N.tif {DATA}/out-Band3N.xml \
{DATA}/out-Band3N_ortho.tif
!mapproject --t_srs {T_SRS} --tr 15 \
{REF_DEM} \
{DATA}/out-Band3B.tif {DATA}/out-Band3B.xml \
{DATA}/out-Band3B_ortho.tif
!parallel_stereo -t aster \
--stereo-algorithm asp_mgm \
--subpixel-mode 9 \
--dem {REF_DEM} \
--processes 1 --threads-multiprocess 4 \
{DATA}/out-Band3N_ortho.tif {DATA}/out-Band3B_ortho.tif \
{DATA}/out-Band3N.xml {DATA}/out-Band3B.xml \
{DATA}/stereo_ortho/run
!point2dem --tr 30 -r earth --auto-proj-center --errorimage {DATA}/stereo_ortho/run-PC.tif
!ls -lh {DATA}/stereo_ortho/run-DEM.tif
7. Second report#
Same report against the orthorectified DEM, now with the Copernicus DEM as the reference for difference maps.
--reuse_selections points at the sidecar the first report left behind and replays its figure choices — the same ICESat-2 sample points, profile track, and hillshade crops. The two reports then line up panel for panel, so the comparison reflects the processing change rather than different figure selections.
%%time
if Path(f"{DATA}/stereo_ortho/rainier_aster_ortho_report.pdf").exists():
print(f"{DATA}/stereo_ortho/rainier_aster_ortho_report.pdf exists — skipping asp_plot CLI. Delete it to regenerate.")
else:
prior = f"{DATA}/stereo/rainier_aster_report_figure_selections.yml"
reuse = f"--reuse_selections {prior}" if Path(prior).exists() else ""
!asp_plot \
--directory {DATA} \
--stereo_directory stereo_ortho \
--reference_dem {REF_DEM} \
--plot_altimetry True \
--plot_geometry False \
--subset_km 5 \
{reuse} \
--report_filename rainier_aster_ortho_report.pdf
The reports are at:
What’s next#
→ Tutorial 2: WorldView-3 UCSD adds high-resolution commercial imagery, cropping, and ICESat-2 alignment. Tutorial 3 adds bundle adjustment on top of it.
→ For deeper ASTER processing (jitter correction, full bundle adjust), see asp-plot’s ASTER notebooks.