16.5. bundle_adjust

The bundle_adjust program performs bundle adjustment on a given set of images and cameras. An introduction to bundle adjustment, and some advanced usage, including solving for intrinsics, can be found in Section 12.

If it is desired to process a large number of images, consider using parallel_bundle_adjust (Section 16.49).

This tool solves a least squares problem (Section 16.5.8). It uses Google’s Ceres Solver.

Usage:

bundle_adjust [options]             \
   <images> <cameras>               \
   <optional ground control points> \
   -o <output prefix>

16.5.1. Examples

16.5.1.1. ISIS cameras

See Section 4.2 for an introduction to these cameras.

bundle_adjust                   \
  --camera-weight 0             \
  --tri-weight 0.1              \
  --tri-robust-threshold 0.1    \
  file1.cub file2.cub file3.cub \
  -o run_ba/run

The above choices for camera weight and triangulation weight have in the meantime become the defaults. These are helpful in preventing the cameras from drifting too far from initial locations.

How to use the adjusted cameras is shown in Section 16.5.2.

16.5.1.2. Maxar Earth cameras and GCP

Here we use Maxar (DigitalGlobe) Earth data (Section 5) and ground control points (Section 16.5.9):

bundle_adjust                \
  --camera-weight 0          \
  --tri-weight 0.1           \
  --num-passes 2             \
  --datum WGS_1984           \
  file1.tif file2.tif        \
  file1.xml file2.xml        \
  gcp1.gcp gcp2.gcp gcp3.gcp \
  --fix-gcp-xyz              \
  -o run_ba/run

How to use the adjusted cameras is shown in Section 16.5.2.

Using the proper value for --datum is very important, otherwise the longitude-latitude-height values in the GCP files will not be interpreted correctly.

There can be more than one GCP file. The option --fix-gcp-xyz fixes the GCP coordinates during optimization. This is useful when the GCP are very accurate. Otherwise set per-GCP sigma.

The residuals for the GCP will be printed at the end of the final_residuals_pointmap.csv file, and flagged with the string # GCP (Section 16.5.11.5).

We invoked the tool with two passes, which also enables removal of outliers (see option --remove-outliers-params, Section 16.5.13).

16.5.1.3. RPC cameras and image lists

Examples for RPC cameras (Section 8.22). With the cameras stored separately:

bundle_adjust -t rpc \
  left.tif right.tif \
  left.xml right.xml \
  -o run_ba/run

With the cameras embedded in the images:

bundle_adjust -t rpc \
  left.tif right.tif \
  -o run_ba/run

How to use the adjusted cameras is shown in Section 16.5.2. How to produce RPC cameras with the adjustments applied to them is discussed in Section 8.22.3.

The images can be also passed in via --image-list and cameras with --camera-list. When the cameras are embedded in the images, the --camera-list option accepts the image files instead.

16.5.1.4. Pinhole cameras

bundle_adjust -t nadirpinhole \
  --inline-adjustments        \
  --camera-weight 0           \
  --tri-weight 0.1            \
  --tri-robust-threshold 0.1  \
  --datum WGS_1984            \
  file1.JPG file2.JPG         \
  file1.tsai file2.tsai       \
  -o run_ba/run

See Section 20.1 for the pinhole camera model format.

Here we assumed that the cameras point towards the planet’s surface and used the nadirpinhole session. If this assumption is not true, one should use the pinhole session or the --no-datum option.

The value of --datum should reflect the planetary body being imaged. If not set, some functionality will not be available. It will be auto-guessed, either based on camera files, input DEM, or camera center (the latter only for Earth, Mars, Moon).

The option --inline-adjustments will save to disk the optimized cameras with adjustments already applied to them. These can be passed directly to parallel_stereo, without using the original cameras and the adjustments as in Section 16.5.2.

16.5.1.5. CSM cameras and outlier removal

bundle_adjust                                 \
  file1.cub file2.cub                         \
  file1.json file2.json                       \
  -t csm                                      \
  --camera-weight 0                           \
  --tri-weight 0.1                            \
  --tri-robust-threshold 0.1                  \
  --remove-outliers-params '75.0 3.0 3.0 5.0' \
  -o run_ba/run

CSM cameras (Section 8.12) can be stored in .json files or in .cub files. After bundle adjustment, updated .json camera files will be written to disk, in addition to .adjust files. See Section 8.12.6 and Section 8.12.7.

Later, use either the original cameras with the computed adjustments (Section 16.5.2), or the updated cameras without the adjustments.

The datum will be read from the camera files.

The option --remove-outliers-params controls how interest points with large reprojection errors are filtered between optimization passes (it takes effect only when --num-passes is more than 1; the default is 2 passes). It expects four values, 'pct factor err1 err2'. A triangulated point (that is not a GCP) is removed when its reprojection error, in pixels, exceeds:

min(max(pct-th percentile * factor, err1), err2)

With the values '75.0 3.0 3.0 5.0' above, points with reprojection error below err1 = 3 pixels are always kept, those above err2 = 5 pixels are always removed, and in between the cutoff is data-driven (three times the 75th percentile of all reprojection errors). Increase these values to keep more points, or decrease them to filter more aggressively.

For outlier removal in GCP files, see the option --max-gcp-reproj-err in Section 16.5.13.

16.5.1.6. Bathymetry correction

When working with underwater terrain, bundle adjustment can model light refraction through water for triangulation of ground points and ground-to-image operations.

Example:

echo left_bathy_mask.tif right_bathy_mask.tif > mask_list.txt
bundle_adjust                      \
  left_image.tif right_image.tif   \
  left_camera.xml right_camera.xml \
  --bathy-mask-list mask_list.txt  \
  --refraction-index 1.333         \
  --bathy-plane bathy_plane.txt    \
  -o run/run

The mask files must be in a list to distinguish them from the image files. Each input image has a corresponding bathy mask, and these entities must be in the same order (and also with the cameras). Lists can also be used for the input images and cameras, via --image-list and --camera-list.

The preparation of bathy masks, the bathy plane (or more than one), and the refraction index are as for stereo processing (Section 8.31). The options invoked above are described in Section 16.5.13.

Inspect carefully the produced report files (Section 16.5.11).

Consider using the option --camera-position-uncertainty for finer control. Also, the bathy plane needs to be recreated with the bundle-adjusted cameras, if using those new cameras for stereo (Section 16.3). Otherwise a tilt may be present with the old plane.

16.5.1.7. Other cameras

Bundle adjustment supports many other camera models. See Section 8 for the various sensor types.

16.5.2. Use of the results

This program will write the adjustments to the cameras as *.adjust files at a location given by the specified output prefix (Section 16.5.12).

For parallel_stereo to use the adjusted cameras, it should not be passed in the .adjust files. Rather, it should be invoked with the original cameras and the bundle_adjust output prefix via the option --bundle-adjust-prefix. For example:

parallel_stereo file1.cub file2.cub run_stereo/run \
  --bundle-adjust-prefix run_ba/run

The same option can be used with mapprojection (Section 16.41) and some other tools.

Example (for .cub files that contain both the image and the camera):

mapproject --bundle-adjust-prefix run_ba/run \
  input-DEM.tif input.cub output.tif

Example (for cameras in .xml format, so the image and camera are in separate files):

mapproject --bundle-adjust-prefix run_ba/run \
  input-DEM.tif image.tif camera.xml mapped_image.tif

For Pinhole (Section 20.1) and OpticalBar (Section 20.2) cameras, if the --inline-adjustments option is used, the tool will save to disk copies of the input cameras with adjustments already applied to them. These output cameras can then be passed directly to parallel_stereo:

parallel_stereo                               \
  file1.JPG file2.JPG                         \
  run_ba/run-file1.tsai run_ba/run-file2.tsai \
  run_stereo/run

When cameras are of CSM type (Section 8.12), self-contained optimized cameras will be written to disk (Section 8.12.6). These cameras can also be used as-is, so without the --bundle-adjust-prefix option. If the CSM cameras are appended to the .cub files (Section 8.12.7), the updated .cub files can also be used as-is.

To pass adjustments to bundle_adjust itself, use the option --input-adjustments-prefix.

16.5.3. Camera adjustments and applying a transform

The bundle_adjust program can read camera adjustments from a previous run, via --input-adjustments-prefix string. Their format is described in Section 16.5.12.

It can also apply to the input cameras a transform as output by pc_align, via --initial-transform string. This is useful if a DEM produced by ASP was aligned to a ground truth, and it is desired to apply the same alignment to the cameras that were used to create that DEM.

The initial transform can have a rotation, translation, and scale, and it is applied after the input adjustments are read, if those are present. An example is shown in Section 16.53.14.

16.5.4. Validation

The first report file to check after a run concludes is:

{output-prefix}-final_residuals_stats.txt

(Section 16.5.11.1). It will have the mean and median pixel reprojection error for each camera, and their count.

The errors should be under 1 pixel, ideally under 0.5 pixels. The count must be at least a dozen, and ideally more. Otherwise bundle adjustment did not work well.

A fine-grained metric is the triangulation error, computed densely across the images with stereo (Section 14.6.1). A systematic pattern in this error may suggest the need to refine the camera intrinsics (Section 12.2.1).

Other report files are described in Section 16.5.11.

16.5.5. Handling failures

This program will fail if the illumination changes too much between images (see also Section 11.10.5).

Various approaches of creation of interest point matches are presented in Section 16.5.7.3 (the existing ones should be deleted first). Use stereo_gui (Section 16.72.9.2) to inspect the matches.

To make the program work harder at reducing big pixel reprojection errors, the --robust-threshold can be increased, perhaps to 2.0. This may result in the smallest reprojection errors increasing.

16.5.6. Constraints

The primary goal of bundle adjustment is to minimize the pixel reprojection errors, so that the cameras are consistent with each other and with triangulated points.

To ensure the cameras and triangulated points do not drift, ground constraints are set by default. They are meant to be rather soft, to not prevent the reduction in reprojection errors.

16.5.6.1. Ground constraints

The option --tri-weight constrains how much the triangulated points move. This is a soft constraint and given less priority than reducing the pixel reprojection errors in the cameras. Its default value is 0.1. An example is in Section 8.27.1.

This constraint adapts appropriately to the number of interest points and the local average ground sample distance.

The measured distances between the initial and final triangulated points are saved to a file (Section 16.5.11.3) and should be inspected. Also check the pixel reprojection errors per camera (Section 16.5.11.1).

The implementation is as follows. The distances between initially triangulated points and those being optimized are computed, then divided by the local averaged ground sample distance (GSD) (to make them into pixel units, like the reprojection errors). These are multiplied by --tri-weight. Then, the robust threshold given by --tri-robust-threshold is applied, with a value of 0.1, to attenuate the big residuals. This threshold is smaller than the pixel reprojection error threshold (--robust-threshold), whose default value is 0.5, to ensure that this constraint does not prevent the optimization from minimizing the pixel reprojection errors.

Triangulated points that are constrained via a DEM (option --heights-from-dem, Section 12.2.1.3), that is, those that are close to a valid portion of this DEM, are not affected by the triangulation constraint.

GCP can be used as well (Section 16.5.9).

16.5.6.2. Camera constraints

The option --camera-position-uncertainty constrains the camera position horizontally and vertically, with given uncertainties, in the local North-East-Down coordinate system of each camera.

The input to this option is a file with one line per image. Each line has the image name, horizontal uncertainty, and the vertical one, separated by spaces. Example:

image1.tif 5.0 10.0
image2.tif 3.0 2.0

All quantities are measured in meters.

To have the same uncertainties for all cameras, pass instead of a file name two values separated by a comma (no spaces). Example: 5.0,10.0 (post 10/2025 build).

It is suggested to overestimate these uncertainties. A strict constraint can prevent the problem from converging to a good solution.

It is suggested to examine the camera change report (Section 16.5.11.2) and pixel reprojection report (Section 16.5.11.1) to see the effect of this constraint.

In the latest build (Section 2.1, post 10/2025), the implementation of this was changed. A sum of squares of quantities such as:

(curr_position - init_position) / uncertainty

is added to the cost function (Section 16.5.8) for each camera. The horizontal and vertical components result in separate terms.

This performs better than prior alternatives, but the camera motion may be perhaps 1-10 times more than expected.

For the jitter solver (Section 16.38) and a linescan camera, such a term exists for each position sample in the camera, and then each is divided (after squaring) by the number of samples.

The advanced option --camera-position-uncertainty-power can be used to change the power to which the normalized position difference is raised before being added to the cost function. The default value is 2. A value such as 4 may result in stricter enforcement of this constraint, but may also make the problem harder to solve. The default behavior is preferred.

It is suggested to avoid the older options --camera-position-weight and --rotation-weight, which will be removed in the future.

16.5.7. Use cases

16.5.7.1. Large-scale bundle adjustment

Bundle adjustment has been tested extensively and used successfully with thousands of frame (pinhole) cameras and with close to 1000 linescan cameras.

Large-scale usage of bundle adjustment is illustrated in the SkySat processing example (Section 8.27), with many Pinhole cameras, and with a large number of linescan Lunar images with variable illumination (Section 11.10).

Attention to choices of parameters and solid validation is needed in such cases. The tool creates report files with various metrics that can help judge how good the solution is (Section 16.5.11).

See also the related jitter-solving program (Section 16.38), and the rig calibrator (Section 16.60).

16.5.7.2. Solving for intrinsics

See Section 12 for how to solve for intrinsics. In particular, see Section 12.2.2 for the case when there exist several sensors, each with its own intrinsics parameters.

16.5.7.3. Well-distributed interest points

When different parts of the image have different properties, such as rock vs snow, additional work may be needed to ensure interest points are created somewhat uniformly. For that, use the option --matches-per-tile:

bundle_adjust image1.tif image2.tif       \
    image1.tsai image2.tsai               \
    --ip-per-tile 300                     \
    --matches-per-tile 100                \
    --max-pairwise-matches 20000          \
    --camera-weight 0 --tri-weight 0.1    \
    --remove-outliers-params '75 3 10 10' \
    -o run_ba/run

For very large images, the number of interest points and matches per tile (whose size is 1024 pixels on the side) should be decreased from the above.

If the images have very different perspectives, it is suggested to create the interest points based on mapprojected images (Section 12.2.4.3).

Uniformly distributed interest points can be produced from stereo disparity. See Section 12.2.4 for more details.

This program supports plain-text match files (Section 19.10).

16.5.7.4. Controlling where interest points are placed

A custom image or mask can be used to define a region where interest points are created (Section 12.2.4.4).

16.5.7.5. Using mapprojected images

For images that have very large variation in elevation, it is suggested to use bundle adjustment with the option --mapprojected-data for creating interest point matches. An example is given in Section 12.2.4.3.

16.5.8. How bundle adjustment works

Features are matched across images. Rays are cast though matching features using the cameras, and triangulation happens, creating points on the ground. More than two rays can meet at one triangulated point, if a feature was successfully identified in more than two images. The triangulated point is projected back in the cameras. The sum of squares of differences (also called residuals) between the pixel coordinates of the features and the locations where the projections in the cameras occur is minimized. To not let outliers dominate, a robust “loss” function is applied to each error term to attenuate the residuals if they are too big. See the Google Ceres documentation on robust cost functions.

The option --cost-function controls the type of loss function, and --robust-threshold option is used to decide at which value of the residuals the attenuation starts to work. The option --min-triangulation-angle is used to eliminate triangulated points for which all the rays converging to it are too close to being parallel. Such rays make the problem less well-behaved. The option --remove-outliers-params is used to filter outliers if more than one optimization pass is used. See Section 16.5.13 for more options. See Section 12 for a longer explanation.

The variables of optimization are the camera positions and orientations, and the triangulated points on the ground. The intrinsics can be optimized as well, either as a single set for all cameras or individually (Section 12.2.1), or per group of cameras (Section 12.2.2).

Triangulated points can be constrained via --tri-weight (Section 16.5.6.1) or --heights-from-dem (with a well-aligned prior DEM, Section 12.2.1.3). The camera positions can be constrained as well (Section 16.5.6.2).

Ground control points can be employed to incorporate measurements as part of the constraints (Section 16.5.9).

16.5.9. Ground control points

Ground control points consist of known points on the ground, together with their pixel locations in one or more images. Their use is to refine, initialize, or transform to desired coordinates the camera poses (Section 16.5.9.2).

GCP can be created with stereo_gui (Section 16.72.12), gcp_gen (Section 16.24), and dem2gcp (Section 16.18). They can be inspected with stereo_gui (Section 16.72.10).

16.5.9.1. GCP file format

A GCP file must end with a .gcp extension, and contain one ground control point per line. Each line must have the following fields:

  • ground control point id (integer)

  • latitude (in degrees)

  • longitude (in degrees)

  • height above datum (in meters), with the datum itself specified separately, via --datum

  • \(x, y, z\) standard deviations (sigma values, three positive floating point numbers, smaller values suggest more reliable measurements, measured in meters)

On the same line, for each image in which the ground control point is visible there should be:

  • image file name

  • column index in image (float, starting from 0)

  • row index in image (float, starting from 0)

  • column and row standard deviations (also called sigma values, two positive floating point numbers, smaller values suggest more reliable measurements, in units of pixel)

The fields can be separated by spaces or commas. Here is a sample representation of a ground control point measurement:

5 23.7 160.1 427.1 1.0 1.0 1.0 image1.tif 124.5 19.7 1.0 1.0 image2.tif 254.3 73.9 1.0 1.0

16.5.9.2. Uses of GCP

One or more .gcp files can be passed to bundle_adjust as shown in Section 16.5.1, together with one or more images and cameras, to refine the camera poses. The option --datum must be set correctly to interpret the GCP.

GCP can also be employed to initialize the cameras (Section 9.5), or to transform them as a group, with the bundle_adjust options --transform-cameras-with-shared-gcp and --transform-cameras-using-gcp. For use with SfM, see Section 9.3.3.

The option --fix-gcp-xyz fixes the GCP coordinates during optimization. This is useful when the GCP are very accurate. Otherwise set per-GCP sigma.

The option --save-cnet-as-gcp can be invoked to save the optimized control network in the GCP format, after outlier filtering. Any input GCP are included in the output. This can be useful for inspecting the final triangulated points. The xyz sigma is 1 meter for regular non-GCP triangulated points and the value of --heights-from-dem-uncertainty for DEM-constrained points. See also --max-gcp-reproj-err for filtering GCP by reprojection error.

When the --use-lon-lat-height-gcp-error flag is set, the three standard deviations are interpreted as applying not to \(x, y, z\) but to latitude, longitude, and height above datum (in this order). Hence, if the latitude and longitude are known accurately, while the height less so, the third standard deviation can be set to something larger.

See Section 16.5.11 for the output files, including for more details about reports for GCP files.

16.5.9.3. Effect on optimization

Each ground control point will result in the following terms being added to the cost function:

\[\frac{(x-x_0)^2}{\sigma_x^2} + \frac{(y-y_0)^2}{\sigma_y^2} + \frac{(z-z_0)^2}{\sigma_z^2}\]

Here, \((x_0, y_0, z_0)\) is the input GCP, \((x, y, z)\) is its version being optimized, and the sigma values are the standard deviations from above. No robust cost function is applied to these error terms (see below).

Note that the cost function normally contains sums of squares of pixel differences (Section 16.5.8), while these terms are dimensionless, if the numerators and denominators are assumed to be in meters. Care should be taken that these terms not be allowed to dominate the cost function at the expense of other terms.

The sums of squares of differences between projections into the cameras of the GCP and the pixel values specified in the GCP file will be added to the bundle adjustment cost function, with each difference being divided by the corresponding pixel standard deviation (sigma). To prevent these from dominating the problem, each such error has a robust cost function applied to it, just as done for the regular reprojection errors without GCP. See the Google Ceres documentation on robust cost functions. See also --cost-function and --robust-threshold option descriptions (Section 16.5.13).

The GCP pixel reprojection errors will be saved as the last lines of the report files ending in pointmap.csv. Differences between initial and optimized GCP will be printed in a report file as well. See Section 16.5.11 for more details.

To not optimize the GCP, use the option --fix-gcp-xyz.

16.5.10. Control network

16.5.10.1. Match files

By default, bundle_adjust will create interest point matches between all pairs of images (see also --auto-overlap-params). These matches are assembled into a control network, in which a triangulated point is associated with features in two or more images. The match files are saved with the specified output prefix and a .match extension.

The naming convention for the match files is:

<output prefix>-<image1>__<image2>.match

where the image names are without the directory name and extension. For example, for two images named input/image1.tif and input/image2.tif, and given the output prefix out/run, the match file will be:

out/run-image1__image2.match

If the image names are long enough that, combined with the output prefix, the resulting file name would exceed the length a file system allows for a single file name, the long parts are shortened in a reproducible, cross-platform way. See the discussion and example in Section 19.11.

If such files have been already produced by a different invocation of bundle_adjust or by other means, they can be loaded by bundle_adjust, parallel_stereo and jitter_solve, with the option --match-files-prefix. In this example, the value of this option would be out/run.

Plain-text match files are supported as well (Section 19.10).

Bundle adjustment also produces outlier-filtered versions of these files, that end with -clean.match. These can be used with the option --clean-match-files-prefix. The option --remove-outliers-params controls the outlier filtering. These share the same base name as the corresponding .match files, including any shortening of long names (Section 19.11), and differ only by ending in -clean.match.

Any such files can be inspected with stereo_gui (Section 16.72.9.2) and converted to text with parse_match_file.py (Section 16.52) or ipmatch (Section 16.37.3).

16.5.10.2. ISIS control network

This program can read and write ISIS jigsaw binary control networks. Example:

bundle_adjust                 \
  --image-list image_list.txt \
  --isis-cnet controlNet.net  \
  -o ba/run

This format makes it possible to handle a very large number of control points.

It is very important that the images in the list be in the order as expected in the control network. A copy of this list will be saved, for the record, in the output directory.

In this mode, bundle_adjust will also write the updated control network in the ISIS format, with the name <output prefix>.net (instead of match files).

If GCP are provided via a .gcp file (Section 16.5.9), these will be added to the optimization and to the output control network.

The option --output-cnet-type explicitly sets the output format for interest point matches. This allows for the input and output formats to be different.

The stereo_gui program (Section 16.72.9.5) can visualize such a control network file.

See Section 12.4 for more technical details. See also ASP’s jigsaw tutorial (Section 12.3).

16.5.10.3. NVM format

The bundle_adjust program can read and write the VisualSfM NVM format for a control network. This helps in interfacing with rig_calibrator (Section 16.60.15) and theia_sfm (Section 16.76). Usage:

bundle_adjust --nvm input.nvm \
  --image-list images.txt     \
  --camera-list cameras.txt   \
  --inline-adjustments        \
  -o ba/run

This will write the file ba/run.nvm having the inlier interest point matches.

The NVM file assumes that the interest points are shifted relative to the optical center of each camera. The optical centers are kept in a separate file ending with _offsets.txt.

The NVM format can be used with any cameras supported by ASP. To export to this format, use --output-cnet-type nvm. Unless this option is explicitly set, the output format is the same as the input format.

If the cameras are of Pinhole (Section 20.1) or CSM Frame (Section 8.12.1) type, the camera poses will be read from the NVM file as well, and the optimized poses will be saved to such a file, unless invoked with --no-poses-from-nvm. The optical centers will be read and written as well. The input cameras must still be provided as above, however, so that the intrinsics can be read. With the option --inline-adjustments, the updated Pinhole camera files will be written separately as well.

For all other types, no camera pose information will be read or written to the NVM file, and the optical centers will be set to half the image dimensions.

16.5.11. Output files

16.5.11.1. Reprojection errors per camera

The initial and final mean and median pixel reprojection error (distance from each interest point and camera projection of the triangulated point) for each camera, and their count, are written to:

{output-prefix}-initial_residuals_stats.txt
{output-prefix}-final_residuals_stats.txt

It is very important to ensure all cameras have a small final reprojection error, ideally under 1 pixel, as otherwise this means that the cameras are not well-registered to each other, or that systematic effects exist, such as uncorrected lens distortion.

See Section 16.5.11.10 for an analogous report at the ground level and Section 16.5.11.5 for finer-grained reporting.

16.5.11.2. Camera position changes

If the --datum option is specified or auto-guessed based on images and cameras, the file:

{output-prefix}-camera_offsets.txt

will be written. It will have, for each camera, the horizontal and vertical component of the difference in camera center before and after optimization, in meters. This is after applying any initial adjustments or transform to the cameras (Section 16.53.14). The local North-East-Down coordinate system of each camera determines the horizontal and vertical components.

This file is useful for understanding how far cameras may move and can help with adding camera constraints (Section 16.5.6.2).

For linescan cameras, the camera centers will be for the upper-left image pixel.

16.5.11.3. Changes in triangulated points

The distance between each initial triangulated point (after applying any initial adjustments or alignment transform, but before any DEM constraint) and final triangulated point (after optimization) are computed (in ECEF, in meters). The mean, median, and count of these distances, per camera, are saved to:

{output-prefix}-triangulation_offsets.txt

This is helpful in understanding how much the triangulated points move. An unreasonable amount of movement may suggest imposing stronger constraints on the triangulated points (Section 16.5.6.1).

16.5.11.4. Convergence angles

The convergence angle percentiles for rays emanating from matching interest points and intersecting on the ground (Section 8.1) are saved to:

{output-prefix}-convergence_angles.txt

There is one entry for each pair of images having matches.

16.5.11.5. Reprojection errors per triangulated point

If the --datum option is specified or auto-guessed based on images and cameras, bundle_adjust will write the triangulated ground position for every feature being matched in two or more images, and the mean pixel reprojection error (Section 12) for each position, before the first and after the last optimization pass, in geodetic coordinates. The files are named

{output-prefix}-initial_residuals_pointmap.csv
{output-prefix}-final_residuals_pointmap.csv

Here is a sample file:

# lon, lat, height_above_datum, mean_residual, num_observations
-55.11690935, -69.34307716, 4.824523817, 0.1141333633, 2

The field num_observations counts in how many images each triangulated point is seen.

Such files can be plotted and overlaid with stereo_gui (Section 16.72.6) to see at which triangulated points the reprojection errors are large and their geographic locations.

Pixel reprojection errors corresponding to GCP will be printed at the end of these files and flagged with the string # GCP.

During the optimization the pixel differences are divided by pixel sigma. This is undone when the pixel reprojection errors are later computed.

The command:

geodiff --absolute --csv-format '1:lon 2:lat 3:height_above_datum' \
  {output-prefix}-final_residuals_pointmap.csv dem.tif

(Section 16.26) can be called to evaluate how well the residuals agree with a given DEM. That can be especially useful if bundle adjustment was invoked with the --heights-from-dem option (Section 12.2.1.3).

One can also invoke point2dem (Section 16.56) with the above --csv-format option to grid these files to create a coarse DEM (also for the error residuals).

The final triangulated positions can be used for alignment with pc_align (Section 16.53). Then, use --min-triangulation-angle 10.0 with bundle adjustment or some other higher value, to filter out unreliable triangulated points. (This still allows, for example, to have a triangulated point obtained by the intersection of three rays, with some of those rays having an angle of at least this while some a much smaller angle.)

16.5.11.6. GCP report

If ground control points are present (Section 16.5.9), the file:

{output-prefix}-gcp-report.csv

will be written. For each GCP it stores the offset between its input (surveyed) and optimized position, split into a ground-plane component and a height component, in meters. This is analogous to the camera position changes (Section 16.5.11.2) and the changes in triangulated points (Section 16.5.11.3).

Here is a sample file:

# GCP offset from initial to optimized GCP (meters)
# lon, lat, ground_offset_m, height_offset_m
# <datum information>
77.478407, 18.567131, 109.36, 0.53

The ground_offset_m field is the norm of the offset in the local ground (tangent) plane, and height_offset_m is the offset along the datum normal. Both are absolute values, computed in the local North-East-Down coordinate system at each GCP.

If the GCP are held fixed with --fix-gcp-xyz, these offsets will be zero.

The reprojection error file (Section 16.5.11.5) can also be helpful. The GCP are flagged there with the string # GCP.

16.5.11.7. Image and camera lists

The list of input images will be saved to:

{output-prefix}-image_list.txt

The list of optimized cameras (such as for CSM cameras or with the option --inline-adjustments for Pinhole cameras) will be saved to:

{output-prefix}-camera_list.txt

If only .adjust files are saved, these will be in the list instead.

This is convenient because both bundle_adjust and jitter_solve can read such lists with the --image-list and --camera-list options (but not if .adjust files are saved).

16.5.11.8. Error propagation

When the option --propagate-errors is specified, propagate the errors (uncertainties) from the input cameras to the triangulated point for each pair of inlier interest point matches. The produced uncertainties will be separated into horizontal and vertical components relative to the datum. Statistical measures will be produced for each pair of images.

The same logic as in stereo triangulation is employed (Section 13), but for the sparse set of interest point matches rather than for the dense image disparity. Since the produced uncertainties depend only weakly on the triangulated surface, computing them for a sparse set of features, and summarizing the statistics, as done here, is usually sufficient.

Specify --horizontal-stddev (a single value for all cameras, measured in meters), to use this as the input camera ground horizontal uncertainty. Otherwise, as in the above-mentioned section, the input errors will be read from camera files, if available.

The produced errors are saved to the file:

{output-prefix}-triangulation_uncertainty.txt

This file will have, for each image pair having matches, the median horizontal and vertical components of the triangulation uncertainties, the mean of each type of uncertainty, the standard deviations, and number of samples used (usually the same as the number of inlier interest points). All errors are in meters.

This operation will use the cameras after bundle adjustment. Invoke with --num-iterations 0 for the original cameras.

It is instructive to compare these uncertainties with their dense counterparts, as produced by point2dem (Section 13.4).

16.5.11.9. Camera positions and orientations

If the cameras are Pinhole and a datum exists, the camera names, camera centers (in meters, in ECEF coordinates), as well as the rotations from each camera to world North-East-Down (NED) coordinates at the camera center are saved to:

{output-prefix}-initial-cameras.csv
{output-prefix}-final-cameras.csv

(before and after optimization; in either case, after any initial transform and/or adjustments are applied). These are useful for analysis when the number of cameras is large and the images are acquired in quick succession (such as for SkySat data, Section 8.27). Note that such a rotation determines a camera’s orientation in NED coordinates. A conversion to geodetic coordinates for the position and to Euler angles for the orientation may help with this data’s interpretation.

16.5.11.10. Registration errors on the ground

If the option --mapproj-dem (with a DEM file as a value) is specified, for each pair of interest point matches (after bundle adjustment and outlier removal) rays will be traced with the optimized cameras, that will be intersected with this DEM. Ideally, these rays should meet the DEM at the same location, so distance between the intersection points measures the amount of misregistration.

The file:

{output-prefix}-mapproj_match_offset_stats.txt

will have the percentiles (25%, 50%, 75%, 85%, 95%) of these distances for all matches in each image against all other images, in meters, and their count.

Do not use this option for any initial evaluation of bundle adjustment. Inspect instead the files mentioned earlier in Section 16.5.11.

This very advanced metric is only helpful if the images are expected to be well-registered to each other and to the DEM, which is not the case without explicit prior alignment. This also expects a rather accurate DEM, and for bundle adjustment to be invoked with the option --heights-from-dem (Section 12.2.1.3).

The 50th percentiles should be on the order of 1 GSD or less.

The file:

{output-prefix}-mapproj_match_offset_pair_stats.txt

saves such measurements for every pair of images.

The full report will be saved to:

{output-prefix}-mapproj_match_offsets.txt

having the longitude, latitude, and height above datum of the midpoint of each pair of intersection points with the DEM, and the distance between them (in meters).

This file is very analogous to the pointmap.csv file, except that these errors are measured on the ground in meters, and not in the cameras in pixels. This file can be displayed and colorized in stereo_gui as a scatterplot (Section 16.72.6).

16.5.12. Format of .adjust files

The bundle_adjust program normally saves external adjustments to the input cameras, or in some cases it creates standalone cameras with adjustments applied internally (Section 16.5.2).

An external adjustment is stored in a .adjust file. It has a translation T as x, y, z (measured in meters) and a rotation R as a quaternion in the order w, x, y, z. The rotation is around the camera center C for pixel (0, 0) (for a linescan camera the camera center depends on the pixel). These are applied on top of initial cameras.

Hence, if P is a point in ECEF, that is, the world in which the camera exists, and an adjustment is applied to the camera, projecting P in the original camera gives the same result as projecting:

P' = R * (P - C) + C + T

in the adjusted camera.

Note that currently the camera center C is not exposed in the .adjust file, so external tools cannot recreate this transform. This will be rectified at a future time.

Adjustments are relative to the initial cameras, so a nominal adjustment has the zero translation and identity rotation (quaternion 1, 0, 0, 0).

16.5.13. Command-line options

16.5.13.1. General

-o, --output-prefix <string (default: “”)>

Prefix for output filenames (see Section 16.5.1 for examples).

-t, --session-type <string (default: “”)>

Select the stereo session type to use for processing. Usually the program can select this automatically by the file extension, except for xml cameras. See Section 16.51.8 for options.

--image-list <string (default: “”)>

A file containing the list of images, when they are too many to specify on the command line. Use in the file a space or newline as separator. When solving for intrinsics for several sensors, pass to this option several lists, with comma as separator between the file names (no space). An example is in Section 12.2.2. See also --camera-list and --mapprojected-data-list.

--camera-list <string (default: “”)>

A file containing the list of cameras, when they are too many to specify on the command line. If the images have embedded camera information, such as for ISIS, this file may be omitted, or specify the image names instead of camera names.

--datum <string (default: “”)>

Set the datum. This will override the datum from the input images and also --t_srs, --semi-major-axis, and --semi-minor-axis. If not set or inferred from the images or camera models, the datum will be auto-guessed based on camera centers for Earth, Mars, and Moon. Options:

  • WGS_1984

  • D_MOON (1,737,400 meters)

  • D_MARS (3,396,190 meters)

  • MOLA (3,396,000 meters)

  • NAD83

  • WGS72

  • NAD27

  • Earth (alias for WGS_1984)

  • Mars (alias for D_MARS)

  • Moon (alias for D_MOON)

--semi-major-axis <float (default: 0)>

Explicitly set the datum semi-major axis in meters.

--semi-minor-axis <float (default: 0)>

Explicitly set the datum semi-minor axis in meters.

--csv-format <string (default: “”)>

Specify the format of input CSV files as a list of entries column_index:column_type (indices start from 1). Examples: 1:x 2:y 3:z (a Cartesian coordinate system with origin at planet center is assumed, with the units being in meters), 5:lon 6:lat 7:radius_m (longitude and latitude are in degrees, the radius is measured in meters from planet center), 3:lat 2:lon 1:height_above_datum, 1:easting 2:northing 3:height_above_datum (need to set --csv-srs; the height above datum is in meters). Can also use radius_km for column_type, when it is again measured from planet center. See Section 19.12 for details.

--csv-srs <string (default: “”)>

The PROJ or WKT string for interpreting the entries in input CSV files.

--threads <integer (default: 0)>

Set the number threads to use. 0 means use the default defined in the program or in ~/.vwrc. Note that when using more than one thread and the Ceres option the results will vary slightly each time the tool is run.

--cache-size-mb <integer (default: 1024)>

Set the system cache size, in MB, for each process.

-h, --help

Display the help message.

-v, --version

Display the version of software.

16.5.13.2. Interest point detection

--ip-detect-method <integer (default: 0)>

Choose an interest point detection method from: 0 = OBAloG ([Jak10]), 1 = SIFT (from OpenCV), 2 = ORB (from OpenCV). The SIFT method, unlike OBALoG, produces interest points that are accurate to subpixel level. Remove any existing .vwip files before recomputing interest points with a different method. See also Section 12.2.4.

--ip-per-tile <integer (default: unspecified)>

How many interest points to detect in each \(1024^2\) image tile (default: automatic determination). This is before matching. Not all interest points will have a match. See also --matches-per-tile.

--ip-per-image <integer (default: unspecified)>

How many interest points to detect in each image (default: automatic determination). Can set either this or --ip-per-tile.

--ip-num-ransac-iterations <iterations (default: 1000)>

How many RANSAC iterations to do in interest point matching.

--ip-inlier-factor <double (default: 0.2)>

Inlier factor used to remove outliers with homography filtering and RANSAC. A higher factor will result in more interest points, but perhaps also more outliers.

--ip-uniqueness-threshold <double (default: 0.8)>

A higher threshold will result in more interest points, but perhaps less unique ones.

--epipolar-threshold <double (default: -1)>

Maximum distance from the epipolar line to search for IP matches. If this option isn’t given, it will default to an automatic determination.

--ip-triangulation-max-error <float (default: -1)>

When matching IP, filter out any pairs with a triangulation error higher than this. The triangulation error is the shortest distance between rays. This gets used only when the usual triangulation error filtering fails.

--ip-nodata-radius <integer (default: 4)>

Remove IP near nodata with this radius, in pixels.

--nodata-value <double (default: NaN)>

Pixels with values less than or equal to this number are treated as no-data. This overrides the no-data values from input images.

--individually-normalize

Individually normalize the input images instead of using common values.

--ip-match-radius <integer (default: 0)>

For mapprojected images, before matching, drop interest points that have no counterpart in the other image within this many pixels (after transforming the interest point to the other image’s pixel frame via the georeferences).

--flann-method <string (default: “auto”)>

Choose the FLANN method for matching interest points. Options: kmeans: slower but deterministic, kdtree: faster (up to 6x) but not deterministic (starting with FLANN 1.9.2). The default (auto) is to use kmeans for 25,000 features or less and kdtree otherwise. This does not apply to ORB feature matching.

--save-vwip

Save .vwip files (interest point matches per image, before matching). This option is currently ignored as .vwip are always saved.

16.5.13.3. Interest point matching

--min-matches <integer (default: 5)>

Set the minimum number of matches between images that will be considered.

--max-pairwise-matches <integer (default: 10000)>

Reduce the number of matches per pair of images to at most this number, by selecting a random subset, if needed. This happens when setting up the optimization, and before outlier filtering.

--matches-per-tile <int (default: unspecified)>

How many interest point matches to compute in each image tile (of size normally \(1024^2\) pixels). Use a value of --ip-per-tile a few times larger than this. See an example in Section 16.5.1. See also --matches-per-tile-params.

--matches-per-tile-params <int int (default: 1024 1280)>

To be used with --matches-per-tile. The first value is the image tile size for both images. A larger second value allows each right tile to further expand to this size, resulting in the tiles overlapping. This may be needed if the homography alignment between these images is not great, as this transform is used to pair up left and right image tiles.

--overlap-limit <integer (default: 0)>

Limit the number of subsequent images to search for matches to the current image to this value. By default try to match all images. See also --auto-overlap-params.

--overlap-list <string (default: “”)>

A file containing a list of image pairs, one pair per line, separated by a space, which are expected to overlap. Matches are then computed only among the images in each pair. The order in which pairs are specified is not important.

--auto-overlap-params <string (default: “”)>

Determine which camera images overlap by finding the bounding boxes of their ground footprints given the specified DEM, expanding them by a given percentage, and see if those intersect. A higher percentage should be used when there is more uncertainty about the input camera poses. As of the 10/2025 build, a third parameter can be provided to limit the number of subsequent images that overlap to this many. Example: ‘dem.tif 15.0 6’. Using this with --mapprojected-data will restrict the matching only to the ground-level overlap regions (expanded by this percentage). As of the 10/2025 build, this works also with --match-first-to-last.

--auto-overlap-buffer <double (default: not set)>

Try to automatically determine which images overlap. Used only if this option is explicitly set. Only supports Worldview style XML camera files. The lon-lat footprints of the cameras are expanded outwards on all sides by this value (in degrees), before checking if they intersect.

--match-first-to-last

Match the first several images to last several images by extending the logic of --overlap-limit past the last image to the earliest ones. As of the 10/2025 build, this works also with --auto-overlap-params.

--position-filter-dist <max_dist (default: -1.0)>

If estimated camera positions are used, this option can be used to set a threshold distance in meters between the cameras. If any pair of cameras is farther apart than this distance, the tool will not attempt to find matching interest points between those two cameras.

--enable-rough-homography

Enable the step of performing datum-based rough homography for interest point matching. This is best used with reasonably reliable input cameras and a wide footprint on the ground.

--skip-rough-homography

Skip the step of performing datum-based rough homography. This obsolete option is ignored as it is the default.

--enable-tri-ip-filter

Enable triangulation-based interest points filtering. This is best used with reasonably reliable input cameras.

--disable-tri-ip-filter

Disable triangulation-based interest points filtering. This obsolete option is ignored as is the default.

--no-datum

Do not assume a reliable datum exists, such as for irregularly shaped bodies or when at the ground level. This is also helpful when the input cameras are not very accurate, as the datum is used to do some camera-based filtering of interest points.

16.5.13.4. Match files and control networks

--force-reuse-match-files

Force reusing the match files even if older than the images or cameras. Then the order of images in each interest point match file need not be the same as for input images. Additional match files will be created if needed.

--skip-matching

Only use the match files that be loaded from disk. This implies --force-reuse-match-files.

--matches-as-txt

Read and write match files as plain text instead of binary. See Section 19.10.

--match-files-prefix <string (default: “”)>

Use the match files from this prefix instead of the current output prefix. See the naming convention in Section 16.5.10.1. This implies --skip-matching. The order of images in each interest point match file need not be the same as for input images. See also --clean-match-files-prefix. Cannot be used together with --mapprojected-data or --mapprojected-data-list. Match files among mapprojected images are read only from the output prefix (Section 12.2.4.3).

--clean-match-files-prefix <string (default: “”)>

Use as input the *-clean.match files from this prefix. This implies --skip-matching. The order of images in each interest point match file need not be the same as for input images. Only one of --match-files-prefix and --clean-match-files-prefix can be set. Cannot be used together with --mapprojected-data or --mapprojected-data-list (Section 12.2.4.3).

--isis-cnet <string (default: “”)>

Read a control network having interest point matches from this binary file in the ISIS control network format. This can be used with any images and cameras supported by ASP. See also --output-cnet-type.

--nvm <string (default: “”)>

Read a control network having interest point matches from this file in the NVM format. This can be used with any images and cameras supported by ASP. For Pinhole or CSM frame cameras, the (optimized) camera poses will be read from / written to NVM as well (Section 16.5.10.3). See also --output-cnet-type, --no-poses-from-nvm.

--output-cnet-type <string (default: “”)>

The format in which to save the control network of interest point matches. Options: match-files (match files in ASP’s format), isis-cnet (ISIS jigsaw format), nvm (plain text VisualSfM NVM format). If not set, the same format as for the input is used.

--no-poses-from-nvm

Do not read the camera poses from the NVM file or write them to such a file. Applicable only with the option --nvm and Pinhole camera models.

--save-cnet-as-gcp

Save the optimized control network, after outlier filtering, in the format used by ground control points (Section 16.5.9), including any input GCP. The xyz sigma is 1 meter for regular non-GCP triangulated points and the value of --heights-from-dem-uncertainty for DEM-constrained points. Can be inspected with stereo_gui (Section 16.72.10).

16.5.13.5. Optimization

--cost-function <string (default: Cauchy)>

Choose a cost function from: Cauchy, PseudoHuber, Huber, L1, L2

--robust-threshold <double (default: 0.5)>

Set the threshold for the robust reprojection error cost function. Increasing this makes the solver focus harder on the larger errors while becoming more sensitive to outliers. See the Google Ceres documentation on robust cost functions.

--num-iterations <integer (default: 1000)>

Set the maximum number of iterations.

--parameter-tolerance <double (default: 1e-8)>

Stop when the relative error in the variables being optimized is less than this. When --solve-intrinsics is used, the default is 1e-12.

--num-passes <integer (default: 2)>

How many passes of bundle adjustment to do, with given number of iterations in each pass. For more than one pass, outliers will be removed between passes using --remove-outliers-params, and re-optimization will take place. Residual files and a copy of the match files with the outliers removed (*-clean.match) will be written to disk.

--num-random-passes <integer (default: 0)>

After performing the normal bundle adjustment passes, do this many more passes using the same matches but adding random offsets to the initial parameter values with the goal of avoiding local minima that the optimizer may be getting stuck in. Only the results for the optimization pass with the lowest error are kept.

--save-intermediate-cameras

Save the values for the cameras at each iteration.

16.5.13.6. Outlier filtering

--remove-outliers-params <’pct factor err1 err2’ (default: ‘75.0 3.0 5.0 8.0’)>

Outlier removal based on percentage, when more than one bundle adjustment pass is used. Triangulated points (that are not GCP) with reprojection error in pixels larger than:

min(max(pct-th percentile * factor, err1), err2)

will be removed as outliers. Hence, never remove pixel reprojection errors smaller than err1 but always remove those bigger than err2. Specify as a list in quotes. Also remove outliers based on distribution of interest point matches and triangulated points. See Section 16.5.1.5 for an example.

--elevation-limit <min max (default: auto)>

Remove as outliers interest points (that are not GCP) for which the elevation of the triangulated position (after cameras are optimized) is outside of this range. Specify as two values.

--lon-lat-limit <min_lon min_lat max_lon max_lat (default: auto)>

Remove as outliers interest points (that are not GCP) for which the longitude and latitude of the triangulated position (after cameras are optimized) are outside of this range. Specify as four values.

--max-gcp-reproj-err <double (default: -1.0)>

If positive, after each pass remove GCPs whose mean reprojection error (averaged over all cameras seeing that point) is more than this value (in pixels).

--gcp-robust-threshold <double (default: -1.0)>

If positive, apply a robust cost function (of type --cost-function) to the ground control point (GCP) residuals, with this threshold. The GCP residual is the difference between the optimized and measured GCP position, divided by the GCP sigma from the GCP file. The threshold should be comparable to the largest such normalized residual to expect from reasonable GCP. This attenuates the contribution of noisy GCP. See also --max-gcp-reproj-err.

--min-triangulation-angle <degrees (default: 0.1)>

Filter as outlier any triangulation point for which all rays converging to it have an angle less than this (measured in degrees). This happens on loading the match files and after each optimization pass. This should be used cautiously with very uncertain input cameras. See also --forced-triangulation-distance and --max-triangulation-angle.

--max-triangulation-angle <double (default: -1.0)>

Filter as outlier any triangulation points for which the maximum angle of rays converging to it are more than this (measured in degrees). Set to a positive value. See also --min-triangulation-angle.

--forced-triangulation-distance <meters (default: -1)>

When triangulation fails, for example, when input cameras are inaccurate or the triangulation angle is too small, artificially create a triangulation point this far ahead of the camera, in units of meters. Some of these may later be filtered as outliers. Can also set a very small value for --min-triangulation-angle in this case.

--proj-win <xmin ymin xmax ymax (default: auto)>

Flag as outliers input triangulated points not in this proj win (box in projected units as provided by --proj_str). This should be generous if the input cameras have significant errors.

--proj-str <string (default: “”)>

To be used in conjunction with --proj-win.

16.5.13.7. Camera and ground constraints

--tri-weight <double (default: 0.1)>

The weight to give to the constraint that optimized triangulated points stay close to original triangulated points. A positive value will help ensure the cameras do not move too far, but a large value may prevent convergence. It is suggested to use here 0.1 to 0.5. This will be divided by ground sample distance (GSD) to convert this constraint to pixel units, since the reprojection errors are in pixels. See also --tri-robust-threshold. Does not apply to GCP or points constrained by a DEM.

--tri-robust-threshold <double (default: 0.1)>

The robust threshold to attenuate large differences between initial and optimized triangulation points, after multiplying them by --tri-weight and dividing by GSD. This is less than --robust-threshold, as the primary goal is to reduce pixel reprojection errors, even if that results in big differences in the triangulated points. It is suggested to not modify this value, and adjust instead --tri-weight.

--camera-position-uncertainty <string (default: “”)>

A file having on each line the image name and the horizontal and vertical camera position uncertainty (1 sigma, in meters). This strongly constrains the movement of cameras, potentially at the expense of accuracy. To have the same uncertainties for all cameras, pass instead of a file name two values separated by a comma (no spaces). See Section 16.5.6.2 for an example. See also --camera-position-uncertainty-power.

--camera-position-uncertainty-power <double (default: 2.0)>

A higher value makes the cost function rise more steeply when --camera-position-uncertainty is close to being violated. This is an advanced option. The default should be good enough.

--camera-position-weight <double (default: 0.0)>

A soft constraint to keep the camera positions close to the original values. It is meant to prevent a wholesale shift of the cameras. It can impede the reduction in reprojection errors. It adjusts to the ground sample distance and the number of interest points in the images. The computed discrepancy is attenuated with --camera-position-robust-threshold. It is suggested to use instead --camera-position-uncertainty. See Section 16.5.6.2 for details.

--camera-position-robust-threshold <double (default: 0.1)>

The robust threshold to attenuate large discrepancies between initial and optimized camera positions with the option --camera-position-weight. This is less than --robust-threshold, as the primary goal is to reduce pixel reprojection errors, even if that results in big differences in the camera positions. It is suggested to not modify this value, and adjust instead --camera-position-weight.

--rotation-weight <double (default: 0.0)>

A higher weight will penalize more camera rotation deviations from the original configuration. This adds to the cost function the per-coordinate differences between initial and optimized normalized camera quaternions, multiplied by this weight, and then squared. No robust threshold is used to attenuate this term.

--camera-weight <double (default: 0.0)>

The weight to give to the constraint that the camera positions/orientations stay close to the original values. A higher weight means that the values will change less. This option is deprecated. Use instead --camera-position-weight and --tri-weight.

--heights-from-dem <string (default: “”)>

Assuming the cameras have already been bundle-adjusted and aligned to a known DEM, constrain the triangulated points to be close to the DEM. See also --heights-from-dem-list, --heights-from-dem-uncertainty, and Section 12.2.1.3.

--heights-from-dem-list <string (default: “”)>

Specify a list of DEMs to constrain against, one per line, in a plain text file. This is analogous to --heights-from-dem, but for several DEMs. Useful for co-optimizing over multiple sites. The DEMs may overlap. Where they do and disagree on a point’s height, the first listed DEM is used and a warning is printed.

--heights-from-dem-uncertainty <double (default: -1.0)>

The DEM uncertainty (1 sigma, in meters). Must be positive. A smaller value constrains more the triangulated points to the DEM specified via --heights-from-dem. The discrepancy between a triangulated point and corresponding point on the DEM is divided by this uncertainty to make it dimensionless, before being added to the cost function (Section 16.5.8). See also --heights-from-dem-robust-threshold.

--heights-from-dem-robust-threshold <double (default: 0.1)>

The robust threshold to use to keep the triangulated points close to the DEM if specified via --heights-from-dem. This is applied after the point differences are divided by --heights-from-dem-uncertainty. It will attenuate large height difference outliers. It is suggested to not modify this value, and adjust instead --heights-from-dem-uncertainty.

--weight-image <string (default: “”)>

Given a georeferenced image with float values, for each initial triangulated point find its location in the image and closest pixel value. Multiply the reprojection errors in the cameras for this point by this weight value. The solver will focus more on optimizing points with a higher weight. Points that fall outside the image and weights that are non-positive, NaN, or equal to nodata will be ignored. See Section 12.2.4.4 for details.

--reference-terrain <filename (default: “”)>

An externally provided trustworthy reference terrain to use as a constraint. It can be either a DEM or a point cloud in CSV format. It must be well-aligned with the input cameras (Section 12.2.1.4).

--reference-terrain-weight <double (default: 1)>

How much weight to give to the cost function terms involving the reference terrain. See Section 12.2.1.4.

--max-num-reference-points <integer (default: 100000000)>

Maximum number of (randomly picked) points from the reference terrain to use. See Section 12.2.1.4.

--disparity-list <’filename12 filename23 …’ (default: “”)>

The unaligned disparity files to use when optimizing the intrinsics based on a reference terrain. Specify them as a list in quotes separated by spaces. First file is for the first two images, second is for the second and third images, etc. If an image pair has no disparity file, use ‘none’. See Section 12.2.1.4 for an example.

--max-disp-error <double (default: -1)>

When using a reference terrain as an external control, ignore as outliers xyz points which projected in the left image and transported by disparity to the right image differ by the projection of xyz in the right image by more than this value in pixels. See Section 12.2.1.4.

--fix-gcp-xyz

If the GCP are highly accurate, use this option to not float them during the optimization.

--use-lon-lat-height-gcp-error

When having GCP (or a DEM constraint), constrain the triangulated points in the longitude, latitude, and height space, instead of ECEF. The standard deviations in the GCP file (or DEM uncertainty) are applied accordingly.

16.5.13.8. Solving for intrinsics

--solve-intrinsics

Optimize intrinsic camera parameters. Only used for pinhole, optical bar, and CSM (frame and linescan) cameras. This implies --inline-adjustments. See Section 12.2.1.3 for an example.

--intrinsics-to-float <string (default: “”)>

If solving for intrinsics and is desired to float only a few of them, specify here, in quotes, one or more of: focal_length, optical_center, other_intrinsics (same as distortion). Not specifying anything will float all of them. Also can specify all or none. See Section 12.2.3 for controlling these per each group of cameras sharing a sensor. See also --fixed-distortion-indices.

--intrinsics-to-share <string (default: “”)>

If solving for intrinsics and desired to share only a few of them across all cameras, specify here, in quotes, one or more of: focal_length, optical_center, other_intrinsics (same as distortion). By default all of the intrinsics are shared, so to not share any of them pass in an empty string. Also can specify as all or none. If sharing intrinsics per sensor, this option is ignored, as then the sharing is more fine-grained (Section 12.2.2).

--intrinsics-limits <string (default: “”)>

Set a string in quotes that contains min max ratio pairs for intrinsic parameters. For example, “0.8 1.2” limits the parameter to changing by no more than 20 percent. The first pair is for focal length, the next two are for the center pixel, and the remaining pairs are for other intrinsic parameters. If too many pairs are passed in the program will throw an exception and print the number of intrinsic parameters the cameras use. Cameras adjust all of the parameters in the order they are specified in the camera model unless it is specified otherwise in Section 20.1. Setting limits can greatly slow down the solver.

--min-distortion <double (default: 1e-7)>

Distortion parameters that are optimized and that are smaller in magnitude than this value are set to this value. This is to ensure the parameters are big enough to be optimized. Can be negative. This is affected by --fixed-distortion-indices. Applies to Pinhole cameras (all distortion models) and CSM (radial-tangential distortion only). Does not apply to optical bar models.

--fixed-distortion-indices <string (default: “”)>

A sequence of indices, separated by commas (with no spaces) starting from 0, corresponding to lens distortion parameters to keep fixed, if --solve-intrinsics is invoked. These will not be changed by the --min-distortion setting. Sample input: 0,3,4. The order of distortion parameters is as saved in output camera files. For example, for radial-tangential distortion, the order is k1, k2, p1, p2, k3 (Section 20.1.2).

16.5.13.9. Camera initialization and transforms

--inline-adjustments

If this is set, and the input cameras are of the pinhole or panoramic type, apply the adjustments directly to the cameras, rather than saving them separately as .adjust files.

--input-adjustments-prefix <string (default: “”)>

Prefix to read initial adjustments from, written by a previous invocation of this program.

--initial-transform <string (default: “”)>

Before optimizing the cameras, apply to them the 4 × 4 rotation + translation transform from this file. The transform is in respect to the planet center, such as written by pc_align’s source-to-reference or reference-to-source alignment transform. Set the number of iterations to 0 to stop at this step. If --input-adjustments-prefix is specified, the transform gets applied after the adjustments are read.

--apply-initial-transform-only

Apply to the cameras the transform given by --initial-transform. No iterations, GCP loading, image matching, or report generation take place. Using --num-iterations 0 and without this option will create those.

--fixed-camera-indices <string (default: “”)>

A list of indices, in quotes and starting from 0, with space as separator, corresponding to cameras to keep fixed during the optimization process.

--fixed-image-list <string (default: “”)>

A file having a list of images (separated by spaces or newlines) whose cameras should be fixed during optimization.

--camera-positions <filename (default: “”)>

CSV file containing estimated position of each camera, in ECEF coordinates. For this to work well the camera must travel not along linear path, as this data will be used to find an alignment transform. Only used with the inline-adjustments setting to initialize global camera coordinates. If used, the csv-format setting must also be set. The “file” field is searched for strings that are found in the input image files to match locations to cameras. See Section 9.4 for an example.

--init-camera-using-gcp

Given an image, a pinhole camera lacking correct position and orientation, and a GCP file, find the pinhole camera with given intrinsics most consistent with the GCP (Section 9.5).

--transform-cameras-with-shared-gcp

Given at least 3 GCP, with each seen in at least 2 images, find the triangulated positions based on pixels values in the GCP, and apply a rotation + translation + scale transform to the entire camera system so that the triangulated points get mapped to the ground coordinates in the GCP.

--transform-cameras-using-gcp

Given a set of GCP, with at least two images having at least three GCP each (but with each GCP not shared among the images), transform the cameras to ground coordinates. This is not as robust as --transform-cameras-with-shared-gcp.

--disable-pinhole-gcp-init

Do not try to initialize pinhole camera coordinates using provided GCP coordinates. This is ignored as it is now the default. See also: --init-camera-using-gcp.

--update-isis-cubes-with-csm-state

Save the model state of optimized CSM cameras as part of the .cub files. Any prior version and any SPICE data will be deleted. Mapprojected images obtained with prior version of the cameras must no longer be used in stereo.

--save-adjusted-rpc

In addition to external adjustments to the input cameras, save RPC cameras with the adjustments applied to them, in XML format. This recomputes the RPC models (Section 8.22.3).

16.5.13.10. Mapprojection

--mapprojected-data <string (default: “”)>

Given map-projected versions of the input images and the DEM they were mapprojected onto, create interest point matches between the mapprojected images. Unproject and save those matches, then continue with bundle adjustment. Existing match files will be reused. Specify the mapprojected images and the DEM as a string in quotes, separated by spaces. The order must be same as for the input images. The DEM is optional (since the 1/2026 build) if it can be looked up in the geoheaders of the mapprojected images. If provided, the DEM must be the last file. See Section 12.2.4.3 for an example. It is suggested to use this with --auto-overlap-params. See also --mapprojected-data-list.

--mapprojected-data-list <string (default: “”)>

A file containing the list of mapprojected images and the DEM (see --mapprojected-data), when they are too many to specify on the command line. The order must be the same as for input images. The DEM is optional (since the 1/2026 build) if it can be looked up in the geoheaders of the mapprojected images. If provided, the DEM must be the last entry.

--mapproj-dem <string (default: “”)>

If specified, mapproject every pair of matched interest points onto this DEM and compute their distance, then percentiles of such distances for each image vs the rest and each image pair. This is done after bundle adjustment and outlier removal. Measured in meters. See Section 16.5.11.10 for more details. Not related to --mapprojected-data.

--accept-provided-mapproj-dem

Accept the DEM provided on the command line as the one mapprojection was done with, even if it disagrees with the DEM recorded in the geoheaders of input images.

16.5.13.11. Error propagation

--propagate-errors

Propagate the errors from the input cameras to the triangulated points for all pairs of match points, and produce a report having the median, mean, standard deviation, and number of samples for each camera pair (Section 16.5.11.8).

--horizontal-stddev <double (default: 0.0)>

If positive, propagate this stddev of horizontal ground plane camera uncertainty through triangulation for all cameras. To be used with --propagate-errors.

16.5.13.12. Bathymetry correction

--bathy-plane <string (default: “”)>

Path to a file containing a plane approximating the water surface, for bathymetry correction with underwater terrain (Section 8.31; file format: Section 16.3.10). This corrects camera rays passing through water using Snell’s law. If multiple images are used and they have different water surfaces use --bathy-plane-list. Use together with --refraction-index. See also --bathy-mask-list.

--bathy-plane-list <string (default: “”)>

Path to a file containing a list of bathy plane files for bathymetry correction, if more than one. Set one plane file per line. Must specify one plane per input image, in the same order. See Section 16.3.10 for the file format. Use with --bathy-mask-list and --refraction-index.

--bathy-mask-list <string (default: “”)>

Path to a file containing a list of water mask images for bathymetry correction, one mask per line. Must specify one mask per input image, in the same order. Pixels classified as water must be either no-data or have zero value, while land pixels must have positive values. Must be used with --bathy-plane and --refraction-index. An example is in Section 16.5.1.6.

--refraction-index <double (default: 0.0)>

Index of refraction of water for bathymetry correction. Typical values: 1.333 to 1.341 depending on wavelength and temperature. Must be used with --bathy-plane. See Section 16.59 to compute the effective refraction index for a specific satellite band and water conditions.