diff --git a/nerfstudio/data/utils/colmap_parsing_utils.py b/nerfstudio/data/utils/colmap_parsing_utils.py index 0eeaf6911b..c5afd56892 100644 --- a/nerfstudio/data/utils/colmap_parsing_utils.py +++ b/nerfstudio/data/utils/colmap_parsing_utils.py @@ -399,7 +399,7 @@ def write_points3D_binary(points3D, path_to_model_file): write_next_bytes(fid, pt.id, "Q") write_next_bytes(fid, pt.xyz.tolist(), "ddd") write_next_bytes(fid, pt.rgb.tolist(), "BBB") - write_next_bytes(fid, pt.error, "d") + write_next_bytes(fid, float(pt.error.item()), "d") track_length = pt.image_ids.shape[0] write_next_bytes(fid, track_length, "Q") for image_id, point2D_id in zip(pt.image_ids, pt.point2D_idxs): diff --git a/nerfstudio/plugins/registry.py b/nerfstudio/plugins/registry.py index f50550f74b..380fab25f5 100644 --- a/nerfstudio/plugins/registry.py +++ b/nerfstudio/plugins/registry.py @@ -41,6 +41,11 @@ def discover_methods() -> t.Tuple[t.Dict[str, TrainerConfig], t.Dict[str, str]]: discovered_entry_points = entry_points(group="nerfstudio.method_configs") for name in discovered_entry_points.names: spec = discovered_entry_points[name].load() + + # Support callable (function) entry points to avoid circular imports + if callable(spec): + spec = spec() + if not isinstance(spec, MethodSpecification): CONSOLE.print( f"[bold yellow]Warning: Could not entry point {spec} as it is not an instance of MethodSpecification" diff --git a/nerfstudio/plugins/registry_dataparser.py b/nerfstudio/plugins/registry_dataparser.py index 6b1e34a0f3..1d7011356a 100644 --- a/nerfstudio/plugins/registry_dataparser.py +++ b/nerfstudio/plugins/registry_dataparser.py @@ -57,6 +57,11 @@ def discover_dataparsers() -> t.Tuple[t.Dict[str, DataParserConfig], t.Dict[str, discovered_entry_points = entry_points(group="nerfstudio.dataparser_configs") for name in discovered_entry_points.names: spec = discovered_entry_points[name].load() + + # Support callable (function) entry points to avoid circular imports + if callable(spec): + spec = spec() + if not isinstance(spec, DataParserSpecification): CONSOLE.print( f"[bold yellow]Warning: Could not entry point {spec} as it is not an instance of DataParserSpecification" diff --git a/nerfstudio/process_data/colmap_utils.py b/nerfstudio/process_data/colmap_utils.py index 1d9405c81a..1ae13639eb 100644 --- a/nerfstudio/process_data/colmap_utils.py +++ b/nerfstudio/process_data/colmap_utils.py @@ -64,16 +64,31 @@ def get_colmap_version(colmap_cmd: str, default_version: str = "3.8") -> Version return Version(default_version) -def get_vocab_tree() -> Path: +def get_vocab_tree(colmap_version: Version) -> Path: """Return path to vocab tree. Downloads vocab tree if it doesn't exist. + COLMAP switched from FLANN to faiss for vocabulary tree indexing in 3.12.0 + (June 2025). FLANN- and faiss-based trees are mutually incompatible, so the + correct tree format is selected based on the detected COLMAP version, and + each format is cached under a distinct filename so that upgrading COLMAP + never silently serves a stale tree of the wrong format. + + Args: + colmap_version: The detected COLMAP version, used to choose the tree format. Returns: The path to the vocab tree. """ - vocab_tree_filename = Path(appdirs.user_data_dir("nerfstudio")) / "vocab_tree.fbow" + if colmap_version >= Version("3.12.0"): + vocab_tree_filename = Path(appdirs.user_data_dir("nerfstudio")) / "vocab_tree_faiss_words32K.bin" + vocab_tree_url = ( + "https://github.com/colmap/colmap/releases/download/3.11.1/vocab_tree_faiss_flickr100K_words32K.bin" + ) + else: + vocab_tree_filename = Path(appdirs.user_data_dir("nerfstudio")) / "vocab_tree.fbow" + vocab_tree_url = "https://demuc.de/colmap/vocab_tree_flickr100K_words32K.bin" if not vocab_tree_filename.exists(): - r = requests.get("https://demuc.de/colmap/vocab_tree_flickr100K_words32K.bin", stream=True) + r = requests.get(vocab_tree_url, stream=True) vocab_tree_filename.parent.mkdir(parents=True, exist_ok=True) with open(vocab_tree_filename, "wb") as f: total_length = r.headers.get("content-length") @@ -143,7 +158,7 @@ def run_colmap( f"--SiftMatching.use_gpu {int(gpu)}", ] if matching_method == "vocab_tree": - vocab_tree_filename = get_vocab_tree() + vocab_tree_filename = get_vocab_tree(colmap_version) feature_matcher_cmd.append(f'--VocabTreeMatching.vocab_tree_path "{vocab_tree_filename}"') feature_matcher_cmd = " ".join(feature_matcher_cmd) with status(msg="[bold yellow]Running COLMAP feature matcher...", spinner="runner", verbose=verbose):