Feature detectors and matchers¶
Stabilo registers each frame against the reference by detecting keypoints, matching their descriptors, and fitting a transformation with RANSAC. The detector is selected with detector_name (--detector-name on the CLI) and the matcher with matcher_name (--matcher-name). Six detectors are classical OpenCV algorithms; five are learned models from kornia that download pretrained weights on first use and run on the torch device (--device cpu|cuda|mps, auto picks cuda > mps > cpu).
Comparison¶
detector_name |
Type | Descriptor | Compatible matchers | Speed (CPU) | Rotation invariant | Memory | Acceleration |
|---|---|---|---|---|---|---|---|
orb (default) |
classical, binary | 256-bit | bf, flann |
very fast | ✅ | low | OpenCV CUDA (--gpu) |
sift |
classical, float | 128-d | bf, flann |
medium | ✅ | low | — |
rsift |
classical, float | 128-d (RootSIFT) | bf, flann |
medium | ✅ | low | — |
brisk |
classical, binary | 512-bit | bf, flann |
fast | ✅ | low | — |
kaze |
classical, float | 64-d | bf, flann |
slow | ✅ | low | — |
akaze |
classical, binary | 486-bit | bf, flann |
fast | ✅ | low | — |
xfeat |
learned, sparse | 64-d float | bf, flann |
fast | ❌ | low | torch (--device) |
disk |
learned, sparse | 128-d float | bf, flann, lightglue |
medium | ❌ | high | torch (--device) |
dedode |
learned, sparse | 256-d float | bf, flann, lightglue |
slow | ❌ | high | torch (--device) |
keynet |
learned det. + HardNet desc. | 128-d float | bf, flann, lightglue |
medium | ✅ | high | torch (--device) |
loftr |
learned, detector-free | dense matching | built-in (matcher ignored) | slow | ❌ | very high | torch (--device) |
Every detector keeps at most max_features keypoints in the current frame and ref_multiplier x max_features in the reference frame, the strongest by detector response.
Two limits of the learned detectors¶
Most problems reported with the learned detectors come from one of these two properties. Both belong to the pretrained models, not to stabilo, and neither is something a configuration option can remove.
Rotation: xfeat, disk, dedode, and loftr fail past about 30 degrees
These four are upright models: they were trained on upright imagery and do not estimate a keypoint orientation. Matching degrades as the current frame rotates away from the reference and collapses beyond roughly 30 degrees of in-plane rotation; at 90 degrees all four fail outright, while ORB and SIFT still register to about 1 px.
Footage with large in-plane rotation, such as a drone orbiting or yawing about its own axis, needs a classical detector or keynet, which runs an orientation estimator and is the only rotation-invariant learned option. DeDoDe's C4 and SO2 weight variants are not a workaround: they need a steerer applied at match time, which kornia does not do.
The measured errors per rotation angle are in Usage: Rotation invariance.
Memory: cost grows with the processed frame size, quadratically for loftr
The learned models allocate memory in proportion to the processed frame, which is downsample_ratio² times the input pixel count, and they need far more than the classical detectors: at about 0.5 MP, disk, dedode, keynet, and loftr each peak at several GB of RAM on CPU, while xfeat stays at a few hundred MB.
loftr grows quadratically, because its coarse matching builds an N×N matrix over N = (H/8)·(W/8) tokens. A 4K frame at the default downsample_ratio: 0.5 already needs a 3.9 GB matrix before intermediates, and full resolution needs over 60 GB, enough to freeze a workstation.
Lower downsample_ratio for large inputs. Stabilo warns when the processed frame exceeds the guideline below, but does not cap it:
| Detector | Guideline (processed frame) | Suggested for a 4K input (3840×2160) |
|---|---|---|
xfeat |
2.0 MP | --downsample-ratio 0.49 |
disk, dedode, keynet |
0.5 MP | --downsample-ratio 0.24 |
loftr |
0.3 MP | --downsample-ratio 0.19 |
Running out of memory is raised as an error rather than treated as an unregistrable frame. See Usage: Choosing a downsample ratio.
Matchers¶
matcher_name |
Works with | Notes |
|---|---|---|
bf (default) |
every sparse detector | OpenCV brute-force matcher; Hamming distance for binary descriptors, L2 for float ones. |
flann |
every sparse detector | OpenCV approximate matcher; LSH index for binary descriptors, KD-tree for float ones. |
lightglue |
disk, dedode, keynet |
Learned kornia matcher. It filters its own matches, so filter_type is ignored. It does not support xfeat. |
loftr is detector-free: it matches the image pair directly, so filter_type and the bf/flann choice of matcher_name are ignored when it is selected (lightglue is rejected). For bf and flann, filter_type chooses between no filtering, Lowe's ratio test (the default), and a distance threshold; see Usage: Feature matching and filtering.
Choosing a detector¶
- Start with
orb, the default. It is fast, rotation invariant, light on memory, and the only detector with an OpenCV CUDA path (--gpu, see CUDA). - Use
siftorrsiftwhen ORB finds too few reliable matches, for example on low-texture scenes. - Use
keynetwhen you want a learned detector and the camera may rotate. - Use
xfeat,disk,dedode, orloftronly for footage that stays within about 30 degrees of the reference orientation, with a reduceddownsample_ratio, and preferably on a GPU.
Classical and learned detectors receive the same CLAHE, downsampling, and exclusion-mask handling, and keypoints are always rescaled to full resolution before estimation. The detector-specific options (BRISK, KAZE, and AKAZE thresholds, LoFTR, DISK, and DeDoDe weights) are listed in Usage: Configuration parameters.