Repository navigation
v1.4.2: RANSAC threshold space, reporting of unrecognized arguments - #9
Merged
Merged
Conversation
Keypoints detected on a downsampled frame are rescaled to full resolution before the estimator sees them, so ransac_epipolar_threshold is a full-resolution pixel distance whatever downsample_ratio is, while the keypoint localization error it has to separate arises in the processed image and is magnified by 1 / ratio. The same value is therefore a stricter filter at a low ratio than at a high one, and a threshold tuned at one ratio does not transfer to another. Add ransac_threshold_space, 'full' (the existing behavior, and the default) or 'processed', which passes ransac_epipolar_threshold / downsample_ratio to the estimator and so keeps the threshold fixed in the units the noise is generated in. get_ransac_reproj_threshold() reports the value actually handed to the estimator. The two settings coincide at downsample_ratio 1.0, and no existing configuration changes.
Only the keys of cfg/default.yaml are honoured, so a misspelled parameter had no effect and said nothing: ransac_epipolar_treshold=1.0 ran with the default threshold. Unknown keys are now collected and logged with the nearest valid name. They are warned about rather than raising, because callers that forward a user's configuration block verbatim may carry keys stabilo does not know, and an exception would turn a typo in a downstream configuration into a crash inside the constructor. Behavior is otherwise unchanged: the unknown key is ignored exactly as before and every known key keeps its value. Stabilizer.configurable_keys() exposes the valid names, so a caller can filter or check a configuration against stabilo instead of keeping its own list. The CLI uses it: separate_cli_arguments handed the whole argparse namespace to Stabilizer(**kwargs), including the subcommand's own options, which would now be reported on every invocation. A --custom-config file is not filtered, since a typo there is what the report exists to surface.
…guments usage.md section 11 gains a subsection on why the epipolar threshold does not transfer across downsample ratios and what each threshold space measures, with the two-line example and the parameter table row; section 8 states that a keyword argument outside cfg/default.yaml is ignored and reported, and names configurable_keys(). The README feature list gains the new flag.
Version in __init__.py, CITATION.cff, the README citation block and .zenodo.json; release date 2026-09-17 in CITATION.cff and in the Zenodo "updated" date; the Zenodo related identifier and the embedded README point at the v1.4.2 tree.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two additions that came out of benchmarking stabilo, both with no change to the default pipeline.
The RANSAC threshold's units are now explicit
Keypoints detected on a downsampled frame are rescaled to full resolution before
cv2.findHomographysees them, soransac_epipolar_thresholdis a full-resolution pixel distance whateverdownsample_ratiois. The keypoint localization error it has to separate from real outliers is not: that arises in the processed image and is magnified by1 / downsample_ratioon the way back. The same threshold value is therefore a stricter filter at a low ratio than at a high one, by exactly the ratio between them, and a value tuned at one ratio does not transfer to another. Going from 1.0 to 0.18 makes it about 5.6x stricter relative to that noise.This was never wrong at a fixed ratio, and no result computed at one is affected. It is a confound only when the ratio is swept, which is what a compute-budget axis does.
ransac_threshold_spacenames the convention:'full'(the existing behaviour, and the default) or'processed', which passesransac_epipolar_threshold / downsample_ratioto the estimator and so holds the threshold fixed in the units the noise is generated in. The two coincide atdownsample_ratio: 1.0.get_ransac_reproj_threshold()reports the value actually handed to the estimator, and--ransac-threshold-space/-rtsexposes it on the CLI.Neither convention is right in general: the residuals a threshold separates are part localization noise, which scales with
1 / downsample_ratio, and part model error, which does not. Which dominates is a property of the scenes, so this supplies the mechanism and leaves the choice to whoever tunes it.Unrecognized Stabilizer arguments are reported
_load_configurationhonours only the keys ofcfg/default.yaml, so a misspelled parameter had no effect and said nothing:Stabilizer(ransac_epipolar_treshold=1.0)ran with the default threshold of 2.0. Unknown keys are now collected and logged with the nearest valid name.They are warned about rather than raised on, which is the load-bearing part. Callers that forward a user's configuration block verbatim may carry keys stabilo does not know, so an exception would turn a typo in a downstream configuration into a crash inside this constructor. Behaviour is otherwise unchanged: the unknown key is ignored exactly as before, and every known key keeps its value.
Stabilizer.configurable_keys()exposes the valid set, so a caller can filter or check a configuration against stabilo rather than maintaining its own copy of the list, which drifts as soon as stabilo gains an option.The CLI is the first user of it.
separate_cli_argumentshanded the whole argparse namespace toStabilizer(**kwargs), including the subcommand's own options (the input path,--save, the visualization flags, argparse'sfunc), which the Stabilizer silently dropped; they would now be reported on every invocation. They are filtered againstconfigurable_keys()instead. A--custom-configfile is deliberately not filtered, since a typo there is what the report exists to surface.Documentation
docs/usage.mdsection 11 gains a subsection on why the epipolar threshold does not transfer across downsample ratios, what each threshold space measures, and a two-line example of the same configuration under both. Section 8 states that a keyword argument outsidecfg/default.yamlis ignored and reported, and namesconfigurable_keys(). Thedefault.yamlcomment block above the estimation keys explains the coupling at the point of use, and the README feature list gains the new flag.Compatibility
No behaviour change and no API removal.
ransac_threshold_spacedefaults to'full', which is what every previous version did, and every existing configuration and call produces the same output.Verified on the bundled
tests/ND_before.jpg/ND_after.jpgpair against v1.4.1: identical homography, inlier count, match count and keypoint counts for the stabilo defaults, for geo-trax's registration kwargs, for SIFT atdownsample_ratio: 0.25(the case the threshold change would move if it reached the default path), and for ORB at full resolution. geo-trax's ownestimate_homographywas run against this branch, clean and with a deliberately misspelled key forwarded through it: same homography, no exception, and the new warning naming the key it meant.Same dependency floors and the same Python requirement (>= 3.11) as v1.4.1.
Verification
ruff checkandruff formatunchanged from baselinepython -m buildandtwine checkpass, and the wheel's metadata keeps theLicense,AuthorandMaintainerfields restored in v1.4.1