Skip to content

API reference

The public API is the Stabilizer class, importable as from stabilo import Stabilizer. A typical session calls set_ref_frame() once, then stabilize() per frame, and reads the result with warp_cur_frame(), transform_cur_boxes(), or get_cur_trans_matrix(). The estimated matrix maps the current frame onto the reference frame.

The class attributes named VALID_* list the accepted values of the corresponding options, for example VALID_DETECTORS for detector_name, VALID_MATCHERS for matcher_name, and VALID_DEVICES for device. They are checked when the Stabilizer is created, so they are the de-facto parameter contract.

Stabilizer

Stabilizer(**kwargs)

Stabilize video frames, or the bounding boxes of objects in them, against a reference frame.

Features are detected in the reference frame once and in every current frame, matched, and passed to a robust RANSAC-family estimator. The resulting matrix maps the current frame onto the reference frame; use it to warp the frame, to transform its boxes, or read it directly.

Create a stabilizer and build its detector, matcher, and estimator.

Every option is a keyword argument that defaults to its value in cfg/default.yaml, and Stabilizer.configurable_keys() lists them. A keyword that is not one of them is ignored with a warning naming the nearest valid key. Learned models download their weights on first use.

Other Parameters:

Name Type Description
detector_name str

Feature detector: 'orb', 'sift', 'rsift' (RootSIFT), 'brisk', 'kaze', 'akaze', or a learned one, 'xfeat', 'disk', 'dedode', 'keynet', 'loftr'.

max_features int

Keypoints kept in the current frame, the strongest by response.

ref_multiplier float

The reference frame keeps ref_multiplier x max_features keypoints.

matcher_name str

Descriptor matcher: 'bf', 'flann', or 'lightglue' (with 'disk', 'dedode', or 'keynet' only). 'loftr' matches the image pair itself, so it ignores 'bf' and 'flann' and rejects 'lightglue'.

filter_type str

Match filter: 'none', 'ratio' (Lowe's ratio test), or 'distance'.

filter_ratio float

Lowe's ratio for 'ratio', or the distance-threshold ratio for 'distance'.

match_query_frame str

Whose descriptors are the knnMatch query, 'reference' or 'current'.

transformation_type str

'projective' (3x3 homography) or 'affine' (2x3, partial affine).

ransac_method int

OpenCV robust-estimation flag, a value of VALID_RANSAC_METHODS_DICT (default 38, MAGSAC++). 'affine' supports only 4 (LMEDS) and 8 (RANSAC).

ransac_epipolar_threshold float

Reprojection-error threshold, in the pixels named by ransac_threshold_space.

ransac_threshold_space str

'full' to measure the threshold in full-resolution pixels, or 'processed' to measure it in pixels of the downsampled image, which keeps it fixed relative to keypoint localization noise as downsample_ratio changes.

ransac_max_iter int

Maximum RANSAC iterations.

ransac_confidence float

Required RANSAC confidence level.

mask_use bool

Exclude the boxes passed to set_ref_frame() and stabilize() from feature detection. When False the boxes are discarded.

mask_margin_ratio float

Fraction by which each excluded region is grown.

clahe bool

Apply CLAHE contrast enhancement before detection.

downsample_ratio float

Detect on a frame resized by this factor; keypoints are scaled back to full resolution. Use 1.0 for coordinate-exact work.

gpu bool

OpenCV CUDA acceleration of detection, matching, and warping. Needs a CUDA-enabled OpenCV and a detector in VALID_GPU_DETECTORS.

gpu_device_id int

CUDA device index used when gpu is True.

device str

Torch device for the learned detectors and matchers: 'auto' (cuda, then mps, then cpu), 'cpu', 'cuda', or 'mps'. Independent of gpu.

sift_enable_precise_upscale bool

SIFT and RootSIFT precise sub-pixel upscaling at octave -1.

rsift_eps float

Epsilon added to the L1 norm in RootSIFT descriptor normalization.

brisk_threshold int

BRISK AGAST detection threshold.

kaze_threshold float

KAZE detector response threshold.

akaze_threshold float

AKAZE detector response threshold.

loftr_weights str

LoFTR pretrained weights, 'outdoor' or 'indoor'.

loftr_confidence float

Minimum LoFTR correspondence confidence to keep.

disk_weights str

DISK pretrained weights, 'depth' or 'epipolar'.

dedode_detector_weights str

DeDoDe detector weights.

dedode_descriptor_weights str

DeDoDe descriptor weights.

viz bool

Retain keypoints, masks, and inliers for visualization.

benchmark bool

Fall back to the identity matrix instead of the last known one when estimation fails, and skip the resolution warning and the update check.

min_good_match_count_warning int

Warn when fewer good matches than this are found.

min_inliers_match_count_warning int

Warn when fewer inliers than this are found.

logger Logger

Logger that receives every message, instead of stabilo's own. It is not a configuration key.

Raises:

Type Description
ValueError

If an option is out of range, or options are incompatible (for example gpu=True with a learned detector, or 'affine' with an unsupported ransac_method).

VALID_DETECTORS class-attribute instance-attribute

VALID_DETECTORS = ['orb', 'sift', 'rsift', 'brisk', 'kaze', 'akaze', 'xfeat', 'disk', 'dedode', 'keynet', 'loftr']

VALID_GPU_DETECTORS class-attribute instance-attribute

VALID_GPU_DETECTORS = {'orb'}

DL_DETECTORS class-attribute instance-attribute

DL_DETECTORS = {'xfeat', 'disk', 'dedode', 'keynet', 'loftr'}

SPARSE_DL_DETECTORS class-attribute instance-attribute

SPARSE_DL_DETECTORS = {'xfeat', 'disk', 'dedode', 'keynet'}

VALID_MATCHERS class-attribute instance-attribute

VALID_MATCHERS = ['bf', 'flann', 'lightglue']

VALID_DEVICES class-attribute instance-attribute

VALID_DEVICES = ['auto', 'cpu', 'cuda', 'mps']

LIGHTGLUE_FEATURE_NAMES class-attribute instance-attribute

LIGHTGLUE_FEATURE_NAMES = {'disk': 'disk', 'dedode': 'dedodeg', 'keynet': 'keynet_affnet_hardnet'}

DL_PIXEL_BUDGETS class-attribute instance-attribute

DL_PIXEL_BUDGETS = {'xfeat': 2000000, 'disk': 500000, 'dedode': 500000, 'keynet': 500000, 'loftr': 300000}

VALID_FILTER_TYPES class-attribute instance-attribute

VALID_FILTER_TYPES = ['none', 'ratio', 'distance']

VALID_TRANSFORMATION_TYPES class-attribute instance-attribute

VALID_TRANSFORMATION_TYPES = ['projective', 'affine']

VALID_MATCH_QUERY_FRAMES class-attribute instance-attribute

VALID_MATCH_QUERY_FRAMES = ['reference', 'current']

VALID_RANSAC_THRESHOLD_SPACES class-attribute instance-attribute

VALID_RANSAC_THRESHOLD_SPACES = ['full', 'processed']

VALID_RANSAC_METHODS_DICT class-attribute instance-attribute

VALID_RANSAC_METHODS_DICT = {'cv2.LMEDS': cv2.LMEDS, 'cv2.RANSAC': cv2.RANSAC, 'cv2.RHO': cv2.RHO, 'cv2.USAC_DEFAULT': cv2.USAC_DEFAULT, 'cv2.USAC_PARALLEL': cv2.USAC_PARALLEL, 'cv2.USAC_FAST': cv2.USAC_FAST, 'cv2.USAC_ACCURATE': cv2.USAC_ACCURATE, 'cv2.USAC_PROSAC': cv2.USAC_PROSAC, 'cv2.USAC_MAGSAC': cv2.USAC_MAGSAC}

RANSAC_METHOD_NAMES class-attribute instance-attribute

RANSAC_METHOD_NAMES = {cv2.LMEDS: 'LMEDS', cv2.RANSAC: 'RANSAC', cv2.RHO: 'RHO', cv2.USAC_DEFAULT: 'USAC-Default (LO-RANSAC)', cv2.USAC_PARALLEL: 'USAC-Parallel (LO-RANSAC)', cv2.USAC_FAST: 'USAC-Fast (LO-RANSAC)', cv2.USAC_ACCURATE: 'USAC-Accurate (GC-RANSAC)', cv2.USAC_PROSAC: 'PROSAC', cv2.USAC_MAGSAC: 'MAGSAC++'}

VALID_AFFINE_RANSAC_METHODS class-attribute instance-attribute

VALID_AFFINE_RANSAC_METHODS = {cv2.LMEDS, cv2.RANSAC}

MASK_COORD_LIMIT class-attribute instance-attribute

MASK_COORD_LIMIT = 2 ** 30

logger instance-attribute

logger = kwargs.pop('logger', None) or logger

configurable_keys classmethod

configurable_keys()

Every key that can be passed to Stabilizer(...) or set in a configuration file.

These are exactly the keys of cfg/default.yaml, which is the single source of truth for the options. logger is not among them: it is a constructor-only argument, popped before the configuration is loaded. Exposed so a caller that forwards a user's configuration can filter or check it against stabilo rather than keeping its own copy of the list, which drifts as soon as stabilo gains an option.

describe_ransac_methods classmethod

describe_ransac_methods(methods=None)

Render RANSAC methods as 'code (Name)' strings, sorted by code.

set_ref_frame

set_ref_frame(frame, boxes=None, box_format='xywh')

Set the frame that every later frame is aligned to, and detect its features.

Call it again to change the reference. The process exits if frame is None.

Parameters:

Name Type Description Default
frame ndarray

BGR image.

required
boxes ndarray

Regions to exclude from feature detection, typically moving objects, one per row in box_format. Ignored when mask_use is False.

None
box_format str

'xywh', 'xywha', 'four', 'polygon', or 'circle'; see create_binary_mask().

'xywh'

stabilize

stabilize(frame, boxes=None, box_format='xywh')

Estimate the transformation that maps a frame onto the reference frame.

Read the result with warp_cur_frame(), transform_cur_boxes(), or get_cur_trans_matrix(). When estimation fails, the last successful matrix is kept (the identity when benchmark is True). The process exits if frame is None.

Parameters:

Name Type Description Default
frame ndarray

BGR image to stabilize.

required
boxes ndarray

Regions to exclude from feature detection, one per row in box_format; these are also the boxes that transform_cur_boxes() maps. Ignored when mask_use is False, in which case transform_cur_boxes() returns None.

None
box_format str

'xywh', 'xywha', 'four', 'polygon', or 'circle'; see create_binary_mask().

'xywh'

process_frame

process_frame(frame, boxes=None, box_format='xywh', is_reference=False)

Store a frame and its boxes, build its exclusion mask, and detect its features.

Called by set_ref_frame() and stabilize(). Returns True; the process exits if frame is None.

get_features_and_descriptors

get_features_and_descriptors(frame, mask=None, ref_frame=False)

Detect keypoints in a frame and describe them, honouring the mask and downsample_ratio.

Returns:

Type Description
tuple

A (keypoints, descriptors, gray_frame) tuple. Keypoints are in full-resolution coordinates and gray_frame is None unless viz is True. All three are None for a None frame or a failed detection, and descriptors is None when no keypoints are found. 'loftr' detects nothing here: it only caches the frame for matching.

get_matches

get_matches(desc1, desc2)

Match two descriptor sets with the configured matcher and filter.

Returns:

Type Description
list

The surviving cv2.DMatch list, with desc1 as the query; empty if either set is None.

calculate_transformation_matrix

calculate_transformation_matrix()

Estimate the current-to-reference matrix from the point correspondences found by stabilize().

Needs at least four correspondences. On failure the matrix falls back to the last known one (the identity when benchmark is True) and the inlier count becomes None.

create_binary_mask

create_binary_mask(boxes, box_format)

Build a detection mask of the reference frame's size that excludes the given regions.

Each region is grown by mask_margin_ratio, and regions with non-finite coordinates are skipped with a warning. The box formats, one region per row:

  • 'xywh': [x_center, y_center, width, height], axis-aligned
  • 'xywha': [x_center, y_center, width, height, angle_degrees], oriented
  • 'four': [x1, y1, x2, y2, x3, y3, x4, y4], four corners, oriented or axis-aligned
  • 'polygon': [x1, y1, ..., xN, yN] per row, or one (N, 2) array per polygon
  • 'circle': [x_center, y_center, radius]

Parameters:

Name Type Description Default
boxes ndarray

Regions to exclude.

required
box_format str

One of the formats above.

required

Returns:

Type Description
ndarray

A uint8 mask, 255 where features may be detected and 0 in the excluded regions.

warp_cur_frame

warp_cur_frame()

Warp the frame last passed to stabilize() onto the reference frame.

Returns:

Type Description
Union[ndarray, None]

The warped frame, the input frame unchanged if no matrix is available yet, or None if there is no current frame.

warp_frame

warp_frame(frame)

Warp a frame onto the reference frame with the current transformation matrix.

Returns:

Type Description
Union[ndarray, None]

The warped frame, at the reference frame's size; the input frame unchanged if no matrix is available yet; None if frame is None.

transform_cur_boxes

transform_cur_boxes(out_box_format='xywh')

Map the boxes last passed to stabilize() into the reference frame.

The boxes must be in 'xywh', 'xywha', or 'four' format.

Parameters:

Name Type Description Default
out_box_format str

'xywh', 'xywha', or 'four'.

'xywh'

Returns:

Type Description
Union[ndarray, None]

The transformed boxes, or None if there are none (including when mask_use is False).

transform_boxes

transform_boxes(boxes, trans_matrix, in_box_format='xywh', out_box_format='xywh')

Transform boxes with a given matrix, of the configured transformation_type.

Parameters:

Name Type Description Default
boxes ndarray

Boxes to transform, one per row.

required
trans_matrix ndarray

3x3 homography or 2x3 affine matrix.

required
in_box_format str

'xywh', 'xywha', or 'four'.

'xywh'
out_box_format str

'xywh', 'xywha', or 'four'. 'xywha' is approximate under non-uniform scaling, so 'four' is preferred.

'xywh'

Returns:

Type Description
Union[ndarray, None]

The transformed boxes in out_box_format; boxes unchanged if trans_matrix is None; None if boxes is None.

get_cur_frame

get_cur_frame()

Return the frame last passed to stabilize(), or None.

get_cur_boxes

get_cur_boxes()

Return the boxes last passed to stabilize(), or None (always None when mask_use is False).

get_cur_trans_matrix

get_cur_trans_matrix()

Return the current-to-reference matrix (3x3 projective or 2x3 affine), or None before the first successful estimation.

get_cur_inliers_count

get_cur_inliers_count()

Return the number of inliers behind the current matrix, or None if estimation failed or has not run.

get_cur_num_matches

get_cur_num_matches()

Return the number of filtered matches (point pairs) passed to the estimator, the denominator of the inlier ratio, or None before the first stabilize().

get_cur_num_keypoints

get_cur_num_keypoints()

Return the keypoint counts as (reference, current); either is None if unavailable.

get_ransac_reproj_threshold

get_ransac_reproj_threshold()

Return the reprojection threshold actually handed to the estimator, in full-resolution pixels.

Correspondences are rescaled to full resolution before estimation, so the estimator's threshold is always a full-resolution distance. With ransac_threshold_space='full' that is ransac_epipolar_threshold itself. With 'processed' the configured value is a processed-image distance, and rescaling multiplies it by 1 / downsample_ratio, exactly as it multiplies the residuals the threshold has to separate. The two agree at downsample_ratio 1.0.

get_basic_info

get_basic_info()

Return the main settings: detector, matcher, filter, transformation type, CLAHE, and mask use.

Configurable keyword arguments

Stabilizer(**kwargs) accepts exactly the keys of stabilo/cfg/default.yaml, reproduced below with their defaults and valid ranges. The same keys can be set in a file passed to the CLI's --custom-config. A keyword argument that is not one of these keys is ignored with a warning that names the nearest valid key; Stabilizer.configurable_keys() returns the valid names. The only other keyword argument is logger, an optional logging.Logger that receives all of stabilo's messages.

# =============================================================================
# stabilo - default configuration
# =============================================================================
# These defaults are tuned for the ORB detector, brute-force (BF) matcher,
# Lowe's ratio test, and a projective transformation, balancing accuracy against
# speed for high-altitude bird's-eye-view (BeV) drone imagery.
#
# They were obtained on a set of BeV drone scenes with associated vehicle masks,
# captured from roughly 150 m altitude. With the projective transformation fixed,
# the remaining parameters were optimized hierarchically. See:
# https://github.com/rfonod/stabilo-optimize
#
# Usage:
#   stabilo config show            # print this file
#   stabilo config copy            # write an editable copy to ./custom.yaml
#   stabilo video <input> --save --custom-config custom.yaml
#
# Only the keys present in this file are configurable. Every key can also be
# passed directly to Stabilizer(...) as a keyword argument. Each parameter is
# documented in more detail in docs/usage.md and in the Stabilizer class
# docstring in stabilo/stabilo.py.
# =============================================================================


# -----------------------------------------------------------------------------
# Feature detection
# -----------------------------------------------------------------------------
# Classical detectors ('orb', 'sift', 'rsift', 'brisk', 'kaze', 'akaze') ship with
# OpenCV. Learning-based detectors ('xfeat', 'disk', 'dedode', 'keynet', 'loftr')
# come from kornia and download pretrained weights on first use (cached under
# torch.hub's directory; set TORCH_HOME to relocate it).
# 'loftr' is detector-free: it matches an image pair directly, so 'matcher_name'
# and 'filter_type' are ignored when it is selected.
#
# Two caveats apply to the learning-based detectors:
#   Rotation. 'xfeat', 'disk', 'dedode', and 'loftr' are upright models; matching
#     collapses once the current frame is rotated more than roughly 30 degrees from
#     the reference frame. Only 'keynet' (which estimates keypoint orientation) and
#     the classical detectors are rotation invariant.
#   Memory. They are far hungrier than the classical detectors at high resolution.
#     Lower 'downsample_ratio' for large inputs; 'loftr' scales quadratically with
#     the pixel count. A warning is emitted when the frame size looks risky.
detector_name: 'orb'  # ['orb', 'sift', 'rsift', 'brisk', 'kaze', 'akaze', 'xfeat', 'disk', 'dedode', 'keynet', 'loftr']
max_features: 2000  # Max. keypoints kept in the current frame, the strongest by response; (0, inf)
ref_multiplier: 2.0  # Reference frame detects ref_multiplier x max_features keypoints; [1.0, inf)

# -----------------------------------------------------------------------------
# Feature matching and filtering
# -----------------------------------------------------------------------------
# 'bf' and 'flann' are OpenCV descriptor matchers. 'lightglue' is a learned matcher
# (kornia) and is only compatible with the 'disk', 'dedode', and 'keynet' detectors;
# it does its own filtering, so 'filter_type' is ignored when it is selected.
matcher_name: 'bf'  # ['bf', 'flann', 'lightglue']
filter_type: 'ratio'  # ['none', 'ratio', 'distance']
filter_ratio: 0.9  # Lowe's ratio ('ratio') or distance-threshold ratio ('distance'); (0.0, 1.0]
match_query_frame: 'reference'  # Which frame's descriptors are the knnMatch query; ['reference', 'current']

# -----------------------------------------------------------------------------
# Transformation estimation
# -----------------------------------------------------------------------------
# The estimated matrix maps the current frame onto the reference frame, so the
# RANSAC reprojection threshold is evaluated in reference-frame pixels.
#
# Which pixels depends on 'ransac_threshold_space'. Keypoints are rescaled to full
# resolution before the estimator sees them, so under 'full' the threshold is a
# full-resolution distance at any 'downsample_ratio', while the localization error
# it separates arises in the processed image and is magnified by 1/downsample_ratio.
# A fixed threshold is therefore stricter at a low ratio, and a value tuned at one
# ratio does not transfer to another. 'processed' measures it in processed-image
# pixels instead, passing ransac_epipolar_threshold / downsample_ratio to the
# estimator. The two agree at downsample_ratio: 1.0. See docs/usage.md section 11.
#
# Not every ransac_method works with every transformation_type. 'projective'
# (cv2.findHomography) accepts all of them, whereas 'affine'
# (cv2.estimateAffinePartial2D) accepts ONLY 4 (LMEDS) and 8 (RANSAC); any other
# code, including the default 38, is rejected when the Stabilizer is created.
transformation_type: 'projective'  # ['projective' (3x3 homography, any ransac_method), 'affine' (2x3, ransac_method 4 or 8 only)]
ransac_method: 38  # [4: LMEDS, 8: RANSAC, 16: RHO, 32: USAC-Default (LO-RANSAC), 33: USAC-Parallel (LO-RANSAC), 35: USAC-Fast (LO-RANSAC), 36: USAC-Accurate (GC-RANSAC), 37: PROSAC, 38: MAGSAC++]
ransac_epipolar_threshold: 2.0  # Reprojection-error threshold, in pixels of ransac_threshold_space; (0.0, inf)
ransac_threshold_space: 'full'  # Pixels ransac_epipolar_threshold is measured in; ['full' (full resolution), 'processed' (downsampled image)]
ransac_max_iter: 5000  # Max. RANSAC iterations; (0, inf)
ransac_confidence: 0.999999  # Required RANSAC confidence level; (0.0, 1.0]

# -----------------------------------------------------------------------------
# Exclusion masks
# -----------------------------------------------------------------------------
# Exclusion masks suppress keypoints on dynamic objects (e.g. moving vehicles),
# which would otherwise drag the estimated transformation with them.
mask_use: true  # Honour the bounding boxes passed to set_ref_frame()/stabilize(); [true, false]
mask_margin_ratio: 0.15  # Fractional margin grown around each exclusion region; [0.0, 1.0]

# -----------------------------------------------------------------------------
# Image pre-processing
# -----------------------------------------------------------------------------
clahe: false  # Apply Contrast Limited Adaptive Histogram Equalization; [true, false]
downsample_ratio: 0.5  # Detect on a resized frame, then rescale keypoints to full resolution; (0.0, 1.0]

# -----------------------------------------------------------------------------
# Hardware acceleration
# -----------------------------------------------------------------------------
# Two independent, mutually exclusive acceleration paths:
#
#   gpu     -> OpenCV CUDA. Accelerates detection, matching, and frame warping for
#              the CLASSICAL detectors. Requires an OpenCV built with CUDA support
#              (see docs/cuda.md); currently only detector_name='orb' is supported.
#              RANSAC always runs on the CPU (OpenCV has no CUDA equivalent).
#
#   device  -> PyTorch device. Selects where the LEARNING-BASED detectors/matchers
#              run. Ignored by the classical detectors. 'auto' picks cuda > mps > cpu.
#
# Setting gpu: true together with a learning-based detector is rejected; use
# device: 'cuda' instead.
gpu: false  # OpenCV CUDA acceleration (classical detectors only); [true, false]
gpu_device_id: 0  # CUDA device index used when gpu is true; [0, inf)
device: 'auto'  # Torch device (learning-based detectors/matchers only); ['auto', 'cpu', 'cuda', 'mps']

# -----------------------------------------------------------------------------
# Detector-specific settings
# -----------------------------------------------------------------------------
# Classical. BRISK/KAZE/AKAZE detect every keypoint whose response exceeds the
# threshold below, then keep the max_features strongest (ref_multiplier x
# max_features in the reference frame), as ORB and SIFT do. The defaults are
# OpenCV's. Lower a threshold if a frame yields fewer keypoints than max_features.
sift_enable_precise_upscale: false  # SIFT/RSIFT: precise sub-pixel upscaling at octave -1; [true, false]
rsift_eps: 0.00000001  # RSIFT: L1-normalization epsilon (1e-8); (0.0, inf)
brisk_threshold: 30  # BRISK: AGAST detection threshold; (0, 255]
kaze_threshold: 0.001  # KAZE: detector response threshold; (0.0, inf)
akaze_threshold: 0.001  # AKAZE: detector response threshold; (0.0, inf)

# Learning-based (kornia). Weights are downloaded on first use and cached by torch.
# The DeDoDe 'G' descriptor is backed by a DINOv2 ViT-L (a 1.2 GB extra download and
# roughly double the memory of 'B') and is not more rotation robust, so 'B' is the
# default. The 'C4'/'SO2' descriptor variants need a steerer at match time, which
# kornia does not apply, so they are no more rotation robust than the upright ones.
loftr_weights: 'outdoor'  # LoFTR: pretrained weights; ['outdoor', 'indoor']
loftr_confidence: 0.0  # LoFTR: min. correspondence confidence to keep; [0.0, 1.0] (0.0 keeps all)
disk_weights: 'depth'  # DISK: pretrained weights; ['depth', 'epipolar']
dedode_detector_weights: 'L-C4-v2'  # DeDoDe: detector weights; ['L-upright', 'L-C4', 'L-SO2', 'L-C4-v2']
dedode_descriptor_weights: 'B-upright'  # DeDoDe: descriptor weights; ['B-upright', 'G-upright', 'B-C4', 'B-SO2', 'G-C4', 'G-SO2']

# -----------------------------------------------------------------------------
# Diagnostics
# -----------------------------------------------------------------------------
viz: false  # Retain keypoints, masks, and inliers for visualization; [true, false]
benchmark: false  # Benchmark mode: fall back to identity, suppress warnings; [true, false]
min_good_match_count_warning: 20  # Warn when fewer than this many good matches are found; [0, inf)
min_inliers_match_count_warning: 10  # Warn when fewer than this many inliers are found; [0, inf)

The meaning of each key is described in Usage: Configuration parameters.