From aeadc7f1bdb2d2db553d95d8b039093d064f8b6d Mon Sep 17 00:00:00 2001 From: birgerbr Date: Wed, 9 Sep 2026 09:26:21 +0200 Subject: [PATCH 1/2] Seed OpenCV's RNG before building the FLANN index --- opensfm/features.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/opensfm/features.py b/opensfm/features.py index 0fb752231..f87454522 100644 --- a/opensfm/features.py +++ b/opensfm/features.py @@ -670,4 +670,11 @@ def build_flann_index(descriptors: NDArray, config: Dict[str, Any]) -> cv2.flann ) # pyrefly: ignore [not-callable] + # Pin OpenCV's RNG so the index is a pure function of (descriptors, + # seed). FLANN's index construction draws from cv::theRNG(), which is + # thread-local and advances between builds, so without this two workers + # build different indexes from identical descriptors and matching is + # not reproducible. + cv2.setRNGSeed(config["flann_random_seed"]) + return context.flann_Index(descriptors, flann_params) From 566bf7dd17e30114525f7ab21972b7cf59c7c885 Mon Sep 17 00:00:00 2001 From: birgerbr Date: Wed, 9 Sep 2026 09:26:22 +0200 Subject: [PATCH 2/2] Expose flann_random_seed --- opensfm/config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/opensfm/config.py b/opensfm/config.py index 372efcc04..bdf30c0da 100644 --- a/opensfm/config.py +++ b/opensfm/config.py @@ -111,6 +111,9 @@ class OpenSfMConfig: flann_tree: int = 8 # Smaller -> Faster (but might lose good matches) flann_checks: int = 20 + # Seed for the RNG that FLANN's index construction draws from. + # Fixed by default so matching is reproducible; see build_flann_index. + flann_random_seed: int = 42 ################################## # Params for BoW matching