16.33. image_calc

This tool can be used to perform simple, per-pixel arithmetic on one or more input images. An arithmetic operation specified on the command line is parsed and applied to each pixel, then the result is written to disk. The tool supports multiple input images but each must be the same size and data type. Input images are restricted to one channel (band). For images with more than one channel, only the first channel will be read.

The pixel in the first image is referred to as var_0, the second as var_1, and so on.

The following symbols are allowed in the arithmetic string: +, -, \*, /, (), min(), max(), pow(), abs(), sign().

The tool also supports certain conditional operations: lt, gt, lte, gte, eq (<, >, <=, >=, == respectively). These must be used in a format like lt(a, b, c, d), which translates to if a < b then c else d. Here, the values of a, b, c, and d can be any variables or constants (Section 16.33.1.5).

An example arithmetic string to be passed via -c is:

"-abs(var_0) + min(58, var_1, var_2) / 2"

The tool respects the normal PEMDAS order of operations except that it parses equal priority operations with right-to-left associativity, so, a * b * c becomes a * (b * c). Parentheses can be used to enforce any preferred order of evaluation.

16.33.1. Examples

16.33.1.1. Apply operation and save pixels as float32

image_calc -c "pow(var_0/3.0, 1.1)" \
  -d float32                        \
  input_image.tif                   \
  -o output_image.tif

16.33.1.2. Apply a mask to an image

Masking applies an existing binary mask to an image, keeping the pixels where the mask is 1 and setting the rest to nodata. Use a conditional operator (see the list above) with a nodata value chosen outside the valid data range:

image_calc -c "eq(var_1, 0, -9999, var_0)" \
  --output-nodata-value -9999              \
  -d float32                               \
  input.tif mask.tif -o output.tif

Here, where the mask is 0 the output becomes -9999 (nodata), otherwise the input value is kept. The image and mask must have the same dimensions.

Setting the masked pixels to a dedicated nodata value, rather than 0, takes care of not mixing up masked pixels with pixels whose value is legitimately 0 (such as sea-level elevation). For this reason, avoid masking by multiplying the image by the mask with a nodata value of 0, as that marks every legitimate 0 as invalid.

16.33.1.3. Create a binary mask via thresholding

Thresholding compares pixel values against a threshold to produce binary decisions. This creates a mask with values of 1 and 0:

thresh=0.27
image_calc -c "gte(var_0, $thresh, 1, 0)" \
  --output-nodata-value -1e+6             \
  -d float32                              \
  input.tif -o output.tif

Here, values greater or equal than the threshold become 1, and the rest become 0. It is suggested to ensure that both the input and output nodata values are different than either 0 or 1, and ideally less than these.

16.33.1.4. Threshold and invalidate pixels below a value

This sets pixels below a threshold to nodata:

thresh=5.2
image_calc -c "max($thresh, var_0)" \
  --output-nodata-value $thresh     \
  -d float32                        \
  input.tif -o output.tif

Pixels with values at or below the threshold become nodata (set to the threshold value), while pixels strictly above the threshold retain their original values.

16.33.1.5. Threshold and invalidate pixels above a value

This sets pixels at or above a threshold to nodata:

thresh=1000
nodata=-10000
image_calc -c "gte(var_0, $thresh, $nodata, var_0)" \
  --output-nodata-value $nodata                     \
  -d float32                                        \
  input.tif -o output.tif

Pixels at or above the threshold become nodata, while pixels below retain their original values.

16.33.1.6. Create an image with random values

image_calc -c "rand(var_0)" -d float32 \
  input.tif -o output.tif

The produced values will be between 0 and 1. Other operations can be combined with this one. For example, one could add a random value multiplied by a constant to the input image.

16.33.1.7. Add a value to the geoheader metadata

image_calc         \
  -c "var_0"       \
  --mo 'VAR1=VAL1' \
  -d float32       \
  input.tif        \
  -o output.tif

If this variable already exists, its value will be overwritten. Other existing variables will be preserved. Use gdalinfo to view the metadata.

As with the GDAL -mo option, a value is everything after the first equal sign, so it may contain spaces and further equal signs. Pass several items in one quoted string, or repeat the option, with one VAR=VALUE pair each time:

image_calc                      \
  -c "var_0"                    \
  --mo 'VAR1=value with spaces' \
  --mo 'VAR2=second value'      \
  -d float32                    \
  input.tif                     \
  -o output.tif

16.33.1.8. Stretch and convert to 8-bit

Linearly stretch the pixel values of a single-channel image to the 0 - 255 range and convert to uint8. The input range is determined by the specified percentiles (default: 2% and 98%), mapping them to 0 and 255. Resulting values are rounded and clamped.

image_calc --stretch input.tif -o output.tif

This is useful for visualizing floating-point data. Customize the bounds with --percentile-range.

See also: colormap (Section 16.14) and hillshade (Section 16.28).

16.33.1.9. Subtract 360 degrees from the longitudes in a GeoTiff file

image_calc -c "var_0"     \
  --longitude-offset -360 \
  -d float32              \
  input.tif -o output.tif

16.33.1.10. Extract disparity bands respecting invalid disparities

ASP produces disparity maps (Section 14.2) with three bands, having the horizontal and vertical disparity, and mask of pixels showing the valid disparity.

Extracting one disparity band with gdal_translate (Section 16.25) makes it hard to see where the disparity is zero but valid, and where it is invalid. This can be disambiguated with image_calc, by using the mask from the third band to set the invalid disparities in a band to nodata.

For that, first extract the three bands from a disparity produced by ASP (Section 19.2), such as F.tif:

for b in 1 2 3; do
  gdal_translate -b $b F.tif F_b${b}.tif
done

Then consider a value t that is larger than any disparity, such as t=1e+6. Add this value to all disparities, apply the mask from the third band, then subtract that value. Invalid values will become equal to -t, which is set as the nodata value.

t=1e+6
for b in 1 2; do
  image_calc -c "(var_0 + $t)*var_1 - $t" \
  --output-nodata-value -$t               \
  F_b${b}.tif F_b3.tif                    \
  -o F_b${b}_nodata.tif
done

The obtained disparity bands can be inspected (and colorized) with stereo_gui (Section 16.71).

As of build 1/2026, this logic is implemented in disparitydebug (Section 16.23), with the option --raw.

16.33.2. Usage

image_calc [options] -c <arithmetic formula> <inputs> -o <output>

16.33.3. Command-line options for image_calc

-c, --calc <string>

The arithmetic string, in quotes. For a single input image, if this is not set, it defaults to var_0 so the identity operation. It is required when there are multiple input images.

-d, --output-data-type <type (default: float32)>

The data type of the output file. Options: uint8, uint16, uint32, int16, int32, float32, float64.

--input-nodata-value <double>

Set the nodata value for the input images, overriding the value in the images, if present.

--output-nodata-value <double>

Manually specify a nodata value for the output image. By default it is read from the first input which has it. If missing, a type-aware default is set: -1e6 for float32 and float64, the smallest int32 for int32, -32768 for int16, and 0 for unsigned types. For floating-point output, -1e6 is set rather than the most negative float value, as that one often prints with reduced precision.

-o, --output-file <string>

Output file name.

--mo <string>

Write metadata to the output file, as with the GDAL -mo option. The option can be repeated. See Section 16.33.1.7 for details and examples.

--longitude-offset <double (default: not specified)>

Add this value to the longitudes in the geoheader (can be used to offset the longitudes by 360 degrees).

--no-georef

Remove any georeference information (useful with subsequent GDAL-based processing).

--stretch

Linearly stretch, round, and clamp the input values to the 0 - 255 range (uint8) based on the specified percentiles. See --percentile-range.

--percentile-range <min max (default: 2 98)>

The percentiles to use for stretching the image to 8-bit. These are double values.

--threads <integer (default: 0)>

Select the number of threads to use for each process. If 0, use the value in ~/.vwrc.

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

Set the system cache size, in MB.

--tile-size <integer (default: 256 256)>

Image tile size used for multi-threaded processing.

--no-bigtiff

Tell GDAL to not create BigTiff files.

--tif-compress <None|LZW|Deflate|Packbits (default: LZW)>

TIFF compression method.

--cog

Write a cloud-optimized GeoTIFF (COG). See Section 6.2.7.

-v, --version

Display the version of software.

-h, --help

Display this help message.