8.15. Chandrayaan-2 lunar orbiter

The example here shows how to create a 3D terrain model with Chandrayaan-2 lunar orbiter data, using both the Orbiter High Resolution Camera (OHRC) and the Terrain Mapping Camera-2 (TMC-2).

This workflow needs ASP 3.7.0 or later, installed via conda together with its bundled ISIS, ALE, and USGSCSM, as described in the environment setup below.

Chandrayaan-2 ISIS data should be downloaded as documented further down.

8.15.1. Environment setup

Install ASP 3.7.0 as documented in Section 2.2. That release ships its own custom-built ISIS 10.0.0, along with custom ALE, USGSCSM, and SpiceQL, with the Chandrayaan-2 camera fixes already included. These are newer than the current public ISIS, ALE, and USGSCSM releases, and are needed for the fore and aft TMC-2 cameras. The conda environment (named asp there) already contains all of them. Activate it and point ISIS at it:

conda activate asp
export ISISROOT=$CONDA_PREFIX

Set the location of the ISIS data area (to be downloaded next):

export ISISDATA=$HOME/projects/isisdata
export ALESPICEROOT=$ISISDATA

The kernel download below uses rclone. If it is not already in the environment, install it with conda install -c conda-forge rclone.

See also the USGS ISIS TMC documentation.

8.15.2. ISIS kernels download

The mission kernels are fetched with downloadIsisData, which is shipped with ISIS:

downloadIsisData chandrayaan2 $ISISDATA

Note that the full chandrayaan2 directory is large (about 200 GB), of which essentially all is reconstructed attitude kernels (ck) covering the entire mission since 2019. For a single OHRC image only one or two ck files are needed. Fetching everything except ck takes only a few hundred MB:

downloadIsisData chandrayaan2 $ISISDATA --exclude="kernels/ck/**"

The command:

rclone --config $ISISROOT/etc/isis/rclone.conf \
  ls chandrayaan2:kernels/ck/

lists all available ck files. This can help pick the ones that span the acquisition time of the products to be processed.

The ck files matching the orbit dates of interest can then be fetched individually with rclone, such as:

rclone                                          \
  --config $ISISROOT/etc/isis/rclone.conf       \
  copy                                          \
  chandrayaan2:kernels/ck/                      \
  $ISISDATA/chandrayaan2/kernels/ck/            \
  --include="ch2_att_27Jul2020_04Sep2020_v1.bc" \
  --include="ch2_att_27Aug2020_04Oct2020_v1.bc" \
  --no-traverse -P

8.15.3. Fetching images

Images, orthoimages, and DEMs for the OHRC and TMC-2 cameras can be downloaded from ISRO.

Each download is a zip. After unzipping, locate the .img and .xml files and move them into a working directory. Keep the original ISRO filenames; a rename can break isisimport.

8.15.4. Orbiter High Resolution Camera

The OHRC instrument is a high-resolution camera with a 0.25 m ground sample distance (GSD). It can adjust its look angle and acquire stereo pairs (Section 8.1).

8.15.4.1. Input data

Download the OHRC stereo pair from ISRO as described in Section 8.15.3. We selected the region of interest to be between 20 and 21 degrees in longitude, and -70 to -67 degrees in latitude. The prefixes are:

ch2_ohr_nrp_20200827T0030107497_d_img_d18
ch2_ohr_nrp_20200827T0226453039_d_img_d18

We also got a TMC-2 orthoimage and corresponding DEM with the prefixes:

ch2_tmc_ndn_20231101T0125121377_d_oth_d18
ch2_tmc_ndn_20231101T0125121377_d_dtm_d18

These are at lower resolution but useful for context.

../_images/chandrayaan2_ohrc_tmc.png

Fig. 8.26 From left to right: The first and second OHRC images, and their approximate extent in the (many times larger) TMC-2 ortho image. Note that the illumination in the TMC-2 ortho image is very different.

8.15.4.2. Preprocessing

The steps below assume the ASP 3.7.0 conda environment, which ships a custom build of ISIS, ALE, and USGSCSM (Section 2.2). If spiceinit or isd_generate -k errors, the active ISIS, ALE, or USGSCSM is likely too old, or a separately installed ISIS is being used instead of the one bundled with ASP. Activate the ASP 3.7.0 environment, or use a recent development ISIS build from 2026.06.07 or later from the dev label of the usgs-astrogeology channel (usgs-astrogeology/label/dev).

Each calibrated image dataset has .img and .xml files, with raw data and a PDS-4 label.

The isisimport command converts the raw image to a .cub file:

isisimport                                             \
  from = ch2_ohr_nrp_20200827T0030107497_d_img_d18.xml \
  to   = ch2_ohr_nrp_20200827T0030107497_d_img_d18.cub

(and same for the second image). The PDS4 template is auto-detected in ISIS 10.

For simplicity, the output cub files are renamed to ohrc/img1.cub and ohrc/img2.cub.

The isisimport command only works with raw images and not with ortho images.

The SPICE kernels are attached with spiceinit:

spiceinit from = ohrc/img1.cub

This expects the SPICE kernels for Chandrayaan-2 to exist locally under $ISISDATA/chandrayaan2/ (see the download instructions above). For more information on ISIS data, see Section 2.3.1 and the links from there.

Next, CSM cameras are created with isd_generate from the ALE package, following the linescan recipe in Section 8.12.2.1:

export ALESPICEROOT=$ISISDATA
isd_generate -k ohrc/img1.cub ohrc/img1.cub
isd_generate -k ohrc/img2.cub ohrc/img2.cub

It is expected that the environment is activated with conda activate, with ISISROOT set to $CONDA_PREFIX, and $ISISDATA and $ALESPICEROOT set, as described in the environment setup section above (not just the environment’s bin directory added to the path). Chandrayaan-2 uses the SpiceQL mission database, and skipping conda activate can make isd_generate crash instead of printing a clear error, as SpiceQL then cannot find its configuration under $CONDA_PREFIX.

Check each produced CSM camera file with cam_test (Section 16.9), against itself and against the .cub camera, before proceeding.

The images can be inspected with stereo_gui (Section 16.73), as:

stereo_gui ohrc/img1.cub ohrc/img2.cub

The resulting cub files are very large, on the order of 12,000 x 101,075 pixels. The full images are processed throughout.

8.15.4.3. Bundle adjustment

We found that these images have notable pointing error, so bundle adjustment (Section 16.5) is needed:

bundle_adjust                           \
  ohrc/img1.cub ohrc/img2.cub           \
  ohrc/img1.json ohrc/img2.json         \
  --num-iterations 100 --num-passes 2   \
  --camera-weight 0 --tri-weight 0.1    \
  --remove-outliers-params "75 3 50 50" \
  --ip-per-image 50000                  \
  --max-pairwise-matches 50000          \
  -o ba/run

This stereo pair has a convergence angle of about 25 degrees (Section 16.5.11.4). Inspect the report files (Section 16.5.11); the reprojection error should be sub-pixel.

../_images/chandrayaan2_ohrc_interest_points.png

Fig. 8.27 The left and right OHRC images, and the clean interest point matches between them. These can be plotted with stereo_gui, Section 16.73.9).

8.15.4.4. Stereo

A first DEM is made from the raw images with local epipolar alignment (Section 17.1.2) and the bundle-adjusted cameras. This is the same approach used for the TMC triplet (Section 8.15.5.6). This method does not require the cameras to be correctly registered to the ground.

This needs build 2026/08/21 (Section 2.1) or later, which improved the robustness of local-epipolar alignment.

parallel_stereo                     \
  --alignment-method local_epipolar \
  --stereo-algorithm asp_mgm        \
  --subpixel-mode 9                 \
  --ip-per-tile 300                 \
  --nodes-list nodes.txt            \
  ohrc/img1.cub ohrc/img2.cub       \
  ba/run-img1.adjusted_state.json   \
  ba/run-img2.adjusted_state.json   \
  stereo/run

A generous --ip-per-tile gives the per-tile local alignment enough interest points on these long, narrow strips, so few tiles are left unmatched.

See Section 8.22 for running on multiple nodes. See Section 6 for the various correlation and subpixel algorithms available.

Make the DEM at 1 m (4x image resolution), with the orthoimage and triangulation error (Section 16.57):

point2dem --tr 1.0 --errorimage --orthoimage \
  stereo/run-PC.tif stereo/run-L.tif

The resulting files are named stereo/run-DEM.tif, stereo/run-DRG.tif, and stereo/run-IntersectionErr.tif.

The deep-shadow crater on this strip has almost no image signal, so stereo leaves an artifact there: a spurious block in the DEM with high triangulation error. Mask it out with the orthoimage, which is near zero in shadow. First build a binary mask that is 1 on lit terrain and 0 in shadow (Section 16.34.1.3):

thresh=0.1
image_calc -c "gte(var_0, $thresh, 1, 0)" \
  --output-nodata-value -1e+6             \
  -d float32                              \
  stereo/run-DRG.tif                      \
  -o stereo/run-shadow_mask.tif

Choose the threshold from the orthoimage histogram, large enough to remove the black crater but not the lit terrain (here 0.1). Then apply the mask to the DEM, the orthoimage, and the triangulation error, which share the same grid (Section 16.34.1.2):

image_calc -c "eq(var_1, 0, -9999, var_0)"      \
  --output-nodata-value -9999                   \
  -d float32                                    \
  stereo/run-DEM.tif stereo/run-shadow_mask.tif \
  -o stereo/run-DEM_masked.tif

The same command is applied to run-DRG.tif and run-IntersectionErr.tif. The masked products are used for all inspection and figures below.

8.15.4.5. Reference DEM

A reference DEM is needed for alignment and mapprojection. Here the choice is a Kaguya TC DTM (~32 m/pixel, Section 8.14.5), which is finer than the wider-area LOLA gridded DEMs. The site is around -68 degrees latitude, within Kaguya’s reach. For the TMC dataset, closer to the pole where Kaguya does not reach (as of 2026-08, though this may change), the polar LOLA product was the better choice (Section 8.15.5.4).

Merge the Kaguya tiles that cover the site into one DEM with dem_mosaic (Section 16.20), and call it ref.tif.

Choose a local projection, centered on the site, that is used for all steps below. Here we use a south polar stereographic projection:

proj="+proj=stere +lat_0=-68.4 +lon_0=20.9 +k=1 +x_0=0 +y_0=0 +R=1737400 +units=m +no_defs"

Convert the reference to this projection if it is not already in it (Section 16.25):

gdalwarp -r cubicspline -t_srs "$proj" kaguya_merged.tif ref.tif

A Kaguya DTM can have holes. Fill them (Section 16.20.2.9) and optionally blur the result (dem_mosaic --dem-blur-sigma 5, Section 16.20.2.6), so the DEM used for mapprojection is gap-free.

8.15.4.6. Alignment to a reference DEM

The cameras must be aligned to the reference DEM’s coordinate system. The OHRC DEM is shifted from the reference by about 2.1 km along the track. DEM alignment is not fully robust, and the best method depends on the data, so it is worth trying more than one (Section 16.54). The robust route here is correlation-based alignment (Section 16.54.3.5): a bounded dense correlation cannot slide globally the way ICP can. It is automated but can be fragile, so inspect the result. Also see the analogous section for TMC (Section 8.15.5.7).

Regrid the OHRC DEM and the reference to the same grid, projection, and extent with gdalwarp (Section 16.25):

gdalwarp -r cubicspline -t_srs "$proj" \
  -te <ref extent> -tr 32 32           \
  stereo/run-DEM.tif ohrc_on_ref.tif

Hillshade both (Section 16.29.1):

gdaldem hillshade -multidirectional ref.tif         ref_hill.tif
gdaldem hillshade -multidirectional ohrc_on_ref.tif src_hill.tif
../_images/chandrayaan2_ohrc_hillshades.png

Fig. 8.28 The regridded OHRC DEM and the Kaguya reference, both hillshaded, with a shared projection, grid, and extent. They must look visually similar for the correlation to succeed. The reference goes beyond the OHRC DEM to take into account the initial misregistration.

Correlate the hillshades (Section 16.17) and extract a dense match file. The search range must large enough to incorporate the expected misalignment (shift). Here the shift was found visually to be about 66 px (2.1 km at 32 m), so --corr-search -100 -100 100 100 is enough. For a larger shift, increase this range. Too large a search range results in slow processing and risks locking onto a wrong solution.

parallel_stereo --correlator-mode    \
  --stereo-algorithm asp_mgm         \
  --subpixel-mode 9                  \
  --corr-kernel 9 9                  \
  --corr-search -100 -100 100 100    \
  --ip-per-image 40000               \
  --num-matches-from-disparity 40000 \
  ref_hill.tif src_hill.tif run_corr/run

Inspect the disparity run_corr/run-F.tif (Section 16.23.2). A smoothly varying, near-constant shift means a good lock. Inspect this dense match file then pass it to pc_align (Section 16.54.3.5):

pc_align --max-displacement -1 --num-iterations 0         \
  --max-num-reference-points 1000000                      \
  --match-file run_corr/run-disp-ref_hill__src_hill.match \
  --initial-transform-from-hillshading rigid              \
  --initial-transform-ransac-params 1000 3                \
  --save-transformed-source-points                        \
  ref.tif ohrc_on_ref.tif -o run_align/run

Grid the aligned cloud run_align/run-trans_source.tif with point2dem and inspect it against the reference and the DEM before alignment.

8.15.4.7. Mapprojection

The transform run_align/run-transform.txt maps the OHRC DEM to the reference. Apply it to the bundle-adjusted cameras (Section 16.54.14), so both cameras move into the reference frame:

bundle_adjust                                     \
  ohrc/img1.cub ohrc/img2.cub                     \
  ba/run-img1.adjusted_state.json                 \
  ba/run-img2.adjusted_state.json                 \
  --initial-transform run_align/run-transform.txt \
  --apply-initial-transform-only                  \
  --inline-adjustments                            \
  -o ba_align/run

Mapproject each image at the native ~0.25 m/pixel resolution onto the reference DEM, with the aligned cameras. The reference is gap-free, so no hole filling is needed. The command for the first image is below; the second is identical with its own cub and camera:

mapproject --tr 0.25                     \
  --t_srs "$proj"                        \
  ref.tif                                \
  ohrc/img1.cub                          \
  ba_align/run-img1.adjusted_state.json  \
  ohrc/img1.map.tif

The projection variable was set earlier in the text. Both mapprojected images inherit the reference DEM’s projection, so they are on a common grid.

8.15.4.8. Stereo with mapprojected images

Run stereo with mapprojected images (Section 6.1.7) and the aligned CSM cameras:

parallel_stereo                         \
  --alignment-method none               \
  --stereo-algorithm asp_mgm            \
  --subpixel-mode 9                     \
  --nodes-list nodes.txt                \
  ohrc/img1.map.tif ohrc/img2.map.tif   \
  ba_align/run-img1.adjusted_state.json \
  ba_align/run-img2.adjusted_state.json \
  stereo_map/run                        \
  ref.tif

Produce the DEM at 1 m per pixel, with the orthoimage and triangulation error:

point2dem --tr 1.0      \
  --t_srs "$proj"       \
  --errorimage          \
  --orthoimage          \
  stereo_map/run-PC.tif \
  stereo_map/run-L.tif

As in the local-epipolar pass, the deep-shadow crater is a data void. Apply the same shadow mask (described above) to the DEM, orthoimage, and triangulation error before inspecting.

../_images/chandrayaan2_ohrc_dem.png

Fig. 8.29 The final DEM (hillshade), orthoimage, and triangulation error (0 to 0.5 m), after masking the shadow crater. The median triangulation error is 0.07 m. The horizontal striping in the error is along-track jitter at the 0.25 m GSD scale, which could be reduced by solving for jitter (Section 16.39).

This is a solid ~65.6 km^2 strip, improving on the first pass in both coverage (65.6 vs 64.2 km^2) and triangulation error (0.070 vs 0.082 m).

8.15.4.9. Vertical accuracy vs LOLA

The reference itself may be slightly offset from LOLA (Section 19.12.3), the global standard, and the DEM inherits that. Difference the created aligned DEM and the reference against the raw LOLA shots (Section 19.12.3, Section 16.26) to check:

geodiff stereo_map/run-DEM_masked.tif lola_shots.csv \
  --csv-format "2:lon 3:lat 4:radius_km" -o dem_vs_lola
../_images/chandrayaan2_ohrc_vertical.png

Fig. 8.30 Final DEM minus Kaguya (raster), and the DEM and Kaguya each minus the LOLA shots, all cropped to the DEM extent and clamped +-10 m. The masked crater is the empty hole. The DEM is essentially unbiased against Kaguya (median -0.02 m) and sub-meter against the raw LOLA shots (-0.47 m). Kaguya itself sits about -0.60 m below LOLA over this area, so the DEM matches true ground about as well as the reference it aligned to; the small residual is that reference offset, not a stereo error.

8.15.4.10. Refinement of alignment to LOLA

The DEM is now within about a meter of LOLA, the global standard. Since it is already in the ballpark, the alignment can be refined directly against the LOLA shots with ordinary point-to-plane ICP (Section 16.54.3), which now converges. Pass the DEM first, as the denser cloud (Section 16.54):

pc_align --max-displacement 250                \
  --csv-format "2:lon 3:lat 4:radius_km"       \
  --save-inv-transformed-reference-points      \
  stereo_map/run-DEM_masked.tif lola_shots.csv \
  -o align_lola/run

Here the DEM is the reference (the denser cloud), so the roles are reversed and the inverse transform maps it onto LOLA. The produced cloud align_lola/run-trans_reference.tif is that DEM in the LOLA frame; grid it with point2dem (Section 16.57) as before. That same inverse transform (Section 16.54.6) can also be applied to the cameras (Section 16.54.14).

The correction is small but real: a north-east-down translation of about (2.6, 1.8, 0.5) meters, with a very small rotation. It is mostly a 3 m horizontal nudge plus a 0.5 m down shift that removes the slight vertical bias (the DEM minus the LOLA shots goes from a median of -0.47 m to about 0) and tightens the fit by roughly 20 percent (NMAD from 1.74 to 1.39 m).

8.15.5. Terrain Mapping Camera-2

The TMC-2 instrument is a 3-line pushbroom camera, with separate forward (fwd), downward-pointing (nadir), and backward (aft) detectors, The look angles differ by about 25 degrees, which is well-suited to stereo. The ground sample distance is about 5 meters at 100 km altitude.

All three detectors record simultaneously, so a substantial ground swath is imaged by all of them.

8.15.5.1. Input data

Download the TMC-2 forward, nadir, and aft stereo triplet from ISRO as described in Section 8.15.3. The three acquisitions cover a shared ground swath on the same orbit pass:

ch2_tmc_ncf_20231101T0125121344_d_img_d18
ch2_tmc_ncn_20231101T0125121377_d_img_d18
ch2_tmc_nca_20231101T0125121377_d_img_d18

Each detector image is about 4000 by 190000 pixels. In this example the site is near the lunar south pole, and the track runs from about -60 to -89 degrees latitude. We process the full track (not a crop) and use all three looks, forming two stereo pairs: fwd-nadir and nadir-aft.

../_images/chandrayaan2_tmc_raw_triplet.png

Fig. 8.31 The three raw TMC-2 looks (forward, nadir, aft), before any mapprojection. These are long and narrow push-broom images. Deeply shadowed terrain is recorded with a pixel value of 0 which is also the nodata value.

8.15.5.2. Preprocessing

These steps require the ASP 3.7.0 conda environment, which ships a custom build of ISIS, ALE, and USGSCSM (Section 2.2).

All three TMC-2 detectors are processed the same way as OHRC above, using the CSM camera models (Section 8.12). Convert each raw image to a cub:

isisimport                                             \
  from = ch2_tmc_ncf_20231101T0125121344_d_img_d18.xml \
  to   = ch2_tmc_ncf_20231101T0125121344_d_img_d18.cub

and the same for the nadir and aft images. For simplicity, the output cub files are renamed to tmc/fwd.cub, tmc/nadir.cub, and tmc/aft.cub. Then attach the kernels and create the CSM camera for each, using isd_generate with the -k option:

spiceinit from = tmc/fwd.cub
isd_generate -k tmc/fwd.cub tmc/fwd.cub

and the same for tmc/nadir.cub and tmc/aft.cub.

An error here likely means that the active ISIS is not the one bundled with ASP 3.7.0, such as a separately installed public ISIS 10.0.0 or 10.0.0_RC2. Alternatively, install a recent development ISIS build from 2026.06.07 or later from the dev label of the usgs-astrogeology channel (usgs-astrogeology/label/dev).

8.15.5.3. Alternative creation of CSM cameras

With older ISIS, skip spiceinit altogether and follow the steps below.

Create for ALE a metakernel under $ALESPICEROOT (which is usually set to $ISISDATA) to locate the SPICE kernels. That is needed since USGS Chandrayaan-2 ISIS data area does not ship one (as of 2026-08-02). Its path should be:

$ISISDATA/chandrayaan2/kernels/mk/ch2_v01.tm

It lists the kernel files. The values in PATH_VALUES should be absolute, due to limitations in ALE, and correct for the local file system. See the NAIF Metakernel reference for the format, and compare with existing .tm files for other missions. Then run isd_generate without the -k option:

export ALESPICEROOT=$ISISDATA
isd_generate tmc/fwd.cub
isd_generate tmc/aft.cub

Check each JSON with cam_test (Section 16.9).

8.15.5.4. Reference DEM

A reference DEM is needed, for alignment and mapprojection.

Near the lunar south pole, a gridded LOLA polar DEM is the natural choice (Section 11.10.2). The product LDEM_60S_120M covers -60 to -90 degrees at 120 m per pixel in one tile, spanning the full track. A Kaguya TC DTM (~32 m/pixel, Section 8.14.5) is at a finer resolution, but does not reach the pole, and the wider-area LOLA products may be coarser than 120 m away from poles. So LDEM_60S_120M at 120 m is the best available reference here. Call it ref.tif.

Choose a local projection that is then used for all steps below. Here we will go with the south polar stereographic projection:

proj="+proj=stere +lat_0=-90 +lon_0=0 +k=1 +x_0=0 +y_0=0 +R=1737400 +units=m +no_defs"

The reference DEM is already in this projection, otherwise it could be converted to it with a command such as:

gdalwarp -r cubicspline -t_srs "$proj" LDEM_60S_120M.tif ref.tif

Such DEMs can be very large. In that case it is suggested to pass an extent to this command with the -te option.

A LOLA gridded DEM is already gap-free. For a reference DEM with holes (such as a prior TMC or Kaguya DTM), fill them (Section 16.20.2.9) and optionally blur the DEM (dem_mosaic --dem-blur-sigma 5, Section 16.20.2.6) before use.

../_images/chandrayaan2_tmc_ref_dem.png

Fig. 8.32 Hillshade of the 120 m LOLA reference DEM, cropped to a region around the area of interest. This is coarse relative to TMC but has the correct absolute geometry, which is needed for alignment and mapprojection.

8.15.5.5. Bundle adjustment

These images have a notable pointing error, so a joint bundle adjustment of the triplet is needed (Section 16.5). The three images (.cub files) and their CSM cameras are passed in the same order:

bundle_adjust                              \
  tmc/fwd.cub tmc/nadir.cub tmc/aft.cub    \
  tmc/fwd.json tmc/nadir.json tmc/aft.json \
  --num-iterations 100 --num-passes 2      \
  --camera-weight 0 --tri-weight 0.1       \
  --remove-outliers-params "75 3 50 50"    \
  --ip-per-tile 400                        \
  --matches-per-tile 200                   \
  --max-pairwise-matches 200000            \
  -o ba/run

Inspect the match files (Section 16.73.9.2), the pixel reprojection errors, and other metrics (Section 16.5.11).

../_images/chandrayaan2_tmc_bundle.png

Fig. 8.33 Pixel reprojection errors per triangulated point, in a local projection. The residuals are sub-pixel almost everywhere.

8.15.5.6. Stereo with local epipolar alignment

A first DEM is produced from the raw images and bundle-adjusted cameras with local_epipolar image alignment (Section 17.1.2). This method does not require the cameras to be correctly registered to the ground but only self-consistent.

This requires build 2026/08/21 or later (Section 2.1), incorporating some robustness fixes for this method.

Run each pair such as:

parallel_stereo                       \
  --alignment-method local_epipolar   \
  --stereo-algorithm asp_mgm          \
  --subpixel-mode 9                   \
  --ip-per-tile 300                   \
  --nodes-list nodes.txt              \
  tmc/fwd.cub tmc/nadir.cub           \
  ba/run-fwd.adjusted_state.json      \
  ba/run-nadir.adjusted_state.json    \
  stereo_fn/run

See Section 8.22 for running on multiple nodes. See Section 6 for the various correlation and subpixel algorithms available.

Run point2dem to produce a DEM at 20 m per pixel (about 4x the input GSD, Section 16.57.4), and to create the triangulation error image (Section 16.57.2.2):

point2dem --tr 20      \
  --t_srs "$proj"      \
  --errorimage         \
  stereo_fn/run-PC.tif \
  stereo_fn/run-L.tif

The projection variable was set earlier in the text.

The two pair DEMs are then merged into one with dem_mosaic (Section 16.20):

dem_mosaic stereo_fn/run-DEM.tif stereo_na/run-DEM.tif \
  -o tmc_merged.tif
../_images/chandrayaan2_tmc_le_dems.png

Fig. 8.34 Left to right: fwd-nadir hillshaded DEM, nadir-aft DEM, fwd-nadir triangulation error (Section 14.6.1), nadir-aft triangulation error. The coverage degrades in shadows. A later plot will have a close-up of a well-lit region.

8.15.5.7. Alignment to LOLA

The cameras must be aligned to the reference DEM’s coordinate system. The merged DEM is shifted from the usual LOLA global reference (here by about 3 km along the track). This is quite large. Aligning to LOLA with the usual ICP point-to-plane method (Section 16.54.3) fails. What worked is to do a coarse alignment first. The best method depends on the data; a narrow swath such as OHRC needs a different one (Section 8.15.4.6).

Coarsen the created merged TMC DEM to the same grid, projection, and extent as ref.tif:

gdalwarp -r average -tr 120 120 -t_srs "$proj" \
  tmc_merged.tif tmc_merged_120m.tif

Overlay this onto ref.tif and inspect both. They should appear similar and with a visible shift.

Here we choose to do a first alignment with sparse matches produced from hillshades (Section 16.54.3.4):

pc_align                                      \
  --initial-transform-from-hillshading rigid  \
  --max-displacement 3000                     \
  --num-iterations 0                          \
  ref.tif tmc_merged_120m.tif                 \
  -o align/seed

If this fails, consider correlation-based alignment (Section 16.54.3.5), with a search range based on the observed shift (Section 14.4.2).

The alignment is refined with point-to-plane ICP, seeded by the first transform:

pc_align                                       \
  --initial-transform align/seed-transform.txt \
  --alignment-method point-to-plane            \
  --max-displacement 300                       \
  --num-iterations 1000                        \
  --save-transformed-source-points             \
  ref.tif tmc_merged_120m.tif                  \
  -o align/run

The output align/run-transform.txt is the combined transform of both calls.

Run point2dem on the transformed source cloud and overlay it on ref.tif for inspection.

Apply that transform to the three cameras, so all of them move into the LOLA frame together (Section 16.54.14):

bundle_adjust                                 \
  tmc/fwd.cub tmc/nadir.cub tmc/aft.cub       \
  ba/run-fwd.adjusted_state.json              \
  ba/run-nadir.adjusted_state.json            \
  ba/run-aft.adjusted_state.json              \
  --initial-transform align/run-transform.txt \
  --apply-initial-transform-only              \
  --inline-adjustments                        \
  -o ba_align/run

8.15.5.8. Mapprojection

Mapproject each cub at the native ~5 m/pixel resolution onto the aligned reference, with the aligned cameras. The command for the forward look is below; the nadir and aft looks are identical with their own cub and camera:

mapproject --tr 5                      \
  --t_srs "$proj"                      \
  ref.tif                              \
  tmc/fwd.cub                          \
  ba_align/run-fwd.adjusted_state.json \
  tmc/fwd.map.tif

The mapprojected images inherit the reference DEM’s projection (the south polar stereographic above), so all three are on a common grid.

Overlay these and the hillshaded reference DEM with georeference information in stereo_gui (Section 16.73) and confirm that they are all in agreement.

../_images/chandrayaan2_tmc_mapproj_inputs.png

Fig. 8.35 The three mapprojected looks (forward, nadir, aft). Areas in shadow are set to no-data and appear black.

8.15.5.9. Stereo with mapprojected images

For each image pair, run stereo with mapprojected images (Section 6.1.7) and the aligned CSM cameras, such as:

parallel_stereo                          \
  --alignment-method none                \
  --stereo-algorithm asp_mgm             \
  --subpixel-mode 9                      \
  --nodes-list nodes.txt                 \
  tmc/fwd.map.tif tmc/nadir.map.tif      \
  ba_align/run-fwd.adjusted_state.json   \
  ba_align/run-nadir.adjusted_state.json \
  stereo_fn_map/run                      \
  ref.tif

Produce DEMs at 20 m per pixel:

point2dem --tr 20 \
  --t_srs "$proj" \
  --errorimage    \
  stereo_fn_map/run-PC.tif

Merge the results as before:

dem_mosaic stereo_fn_map/run-DEM.tif stereo_na_map/run-DEM.tif \
  -o tmc_merged_map.tif
../_images/chandrayaan2_tmc_map_dems.png

Fig. 8.36 Mapprojected-pass DEMs (hillshaded) and triangulation error (0 to 5 m), left to right: fwd-nadir DEM, nadir-aft DEM, fwd-nadir error, nadir-aft error. The triangulation error is visibly lower than in the local-epipolar pass (medians drop by roughly 10 to 25 percent), which is the payoff of mapprojected stereo.

../_images/chandrayaan2_tmc_closeup.png

Fig. 8.37 A close-up DEM after stereo with mapprojection, showing the upper part of the track. The quality is very good on illuminated terrain, with small craters resolved. Results degrade gracefully toward shadowed areas.

8.15.5.10. Evaluation

To validate the results, compare against LOLA. First difference the DEM against the gridded LOLA reference (Section 16.26):

geodiff tmc_merged_map.tif ref.tif -o dem_vs_gridded

then against the raw LOLA shots (Section 19.12.3):

geodiff tmc_merged_map.tif lola_shots.csv \
  --csv-format "2:lon 3:lat 4:radius_km"  \
  -o dem_vs_shots

The horizontal registration against the reference is checked separately: regrid the created DEM and the reference to 120 m with gdalwarp -r average and correlate their hillshades (parallel_stereo --correlator-mode, Section 16.17), which computes horizontal and vertical misregistration in the ground plane. The mean offset is near zero, with a robust spread of about 0.07 pixel.

../_images/chandrayaan2_tmc_dz_dhdv.png

Fig. 8.38 Left to right: the two pair DEMs minus gridded LOLA (the height difference, range +-25 m), then the fwd-nadir alignment residual to gridded 120 m / pixel LOLA, the horizontal (dh) and vertical (dv) components of the disparity in the ground plane (range +-0.5 pixel). The disparity in the ground plane is sub-pixel with no low-frequency structure.

../_images/chandrayaan2_tmc_bias.png

Fig. 8.39 A vertical-bias check, all at +-15 m. Left: merged mapprojected DEM minus gridded LOLA. Middle: the same DEM minus the raw LOLA shots. Right: gridded LOLA minus the raw LOLA shots. The medians are all sub-meter, so there is no constant bias against true ground. A low-amplitude along-track undulation appears in the DEM (left and middle) but not in gridded-minus-shots (right), so it is in the DEM, not LOLA; this is a mild residual-jitter signature that jitter_solve (Section 16.39) could reduce.

8.15.5.11. Refinement of alignment to LOLA

The alignment so far used a coarse reference DEM, which made the process more robust.

It is suggested to refine the alignment of the created DEM against the raw LOLA shots (Section 19.12.3). The created DEM is already within a few meters of raw LOLA, so ordinary point-to-plane ICP (Section 16.54.3) should work.

For this alignment pass, the created DEM goes first, as the denser cloud (Section 16.54):

pc_align --max-displacement 250           \
  --csv-format "2:lon 3:lat 4:radius_km"  \
  --save-inv-transformed-reference-points \
  tmc_merged_map.tif lola_shots.csv       \
  -o align_lola/run

The DEM is the reference, so the inverse transform maps it onto LOLA; the produced cloud align_lola/run-trans_reference.tif is in the LOLA frame. It should be regridded with point2dem (Section 16.57). That same inverse transform (Section 16.54.6) can be applied to the three cameras (Section 16.54.14).

The correction is small: a translation of about 9 m, mostly horizontal (north-east-down of about (2.5, -8.8, 1.3) m), with a negligible rotation. The DEM-minus-LOLA median changed from -0.90 to -0.21 m, and the NMAD from 5.8 to 5.3 m.