From e27bf24e0b69036b4b7f1278dd683804e7b8decd Mon Sep 17 00:00:00 2001 From: igarzonpres Date: Thu, 5 Jun 2025 08:47:02 +0200 Subject: [PATCH 1/3] Add mapper flag for colmap processing --- .../process_data/colmap_converter_to_nerfstudio_dataset.py | 5 +++++ nerfstudio/process_data/colmap_utils.py | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py b/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py index 55f657a3a4..e8c903097f 100644 --- a/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py +++ b/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py @@ -83,6 +83,8 @@ class ColmapConverterToNerfstudioDataset(BaseConverterToNerfstudioDataset): """ colmap_cmd: str = "colmap" """How to call the COLMAP executable.""" + mapper: Literal["colmap", "glomap"] = "colmap" + """Binary to use for the mapping stage. Either ``colmap`` or ``glomap``.""" images_per_equirect: Literal[8, 14] = 8 """Number of samples per image to take from each equirectangular image. Used only when camera-type is equirectangular. @@ -219,6 +221,7 @@ def _run_colmap(self, mask_path: Optional[Path] = None): matching_method=self.matching_method, refine_intrinsics=self.refine_intrinsics, colmap_cmd=self.colmap_cmd, + mapper=self.mapper, ) elif sfm_tool == "hloc": if mask_path is not None: @@ -245,6 +248,8 @@ def __post_init__(self) -> None: super().__post_init__() install_checks.check_ffmpeg_installed() install_checks.check_colmap_installed(self.colmap_cmd) + if self.mapper == "glomap": + install_checks.check_colmap_installed("glomap") if self.crop_bottom < 0.0 or self.crop_bottom > 1: raise RuntimeError("crop_bottom must be set between 0 and 1.") diff --git a/nerfstudio/process_data/colmap_utils.py b/nerfstudio/process_data/colmap_utils.py index 1d9405c81a..38d9acdd35 100644 --- a/nerfstudio/process_data/colmap_utils.py +++ b/nerfstudio/process_data/colmap_utils.py @@ -99,6 +99,7 @@ def run_colmap( matching_method: Literal["vocab_tree", "exhaustive", "sequential"] = "vocab_tree", refine_intrinsics: bool = True, colmap_cmd: str = "colmap", + mapper: Literal["colmap", "glomap"] = "colmap", ) -> None: """Runs COLMAP on the images. @@ -111,7 +112,8 @@ def run_colmap( verbose: If True, logs the output of the command. matching_method: Matching method to use. refine_intrinsics: If True, refine intrinsics. - colmap_cmd: Path to the COLMAP executable. + colmap_cmd: Path to the COLMAP executable for feature extraction and matching. + mapper: Binary to use for the mapping stage ("colmap" or "glomap"). """ colmap_version = get_colmap_version(colmap_cmd) @@ -154,7 +156,7 @@ def run_colmap( sparse_dir = colmap_dir / "sparse" sparse_dir.mkdir(parents=True, exist_ok=True) mapper_cmd = [ - f"{colmap_cmd} mapper", + f"{mapper} mapper", f"--database_path {colmap_dir / 'database.db'}", f"--image_path {image_dir}", f"--output_path {sparse_dir}", From 438c13e518640c6503fb01855ef3c747211dc780 Mon Sep 17 00:00:00 2001 From: igarzonpres Date: Thu, 5 Jun 2025 10:56:15 +0200 Subject: [PATCH 2/3] docs: clarify mapper flag --- .../process_data/colmap_converter_to_nerfstudio_dataset.py | 6 +++++- nerfstudio/process_data/colmap_utils.py | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py b/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py index e8c903097f..78f5dd1300 100644 --- a/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py +++ b/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py @@ -84,7 +84,11 @@ class ColmapConverterToNerfstudioDataset(BaseConverterToNerfstudioDataset): colmap_cmd: str = "colmap" """How to call the COLMAP executable.""" mapper: Literal["colmap", "glomap"] = "colmap" - """Binary to use for the mapping stage. Either ``colmap`` or ``glomap``.""" + """Binary to use for the mapping stage. + + Only the COLMAP ``mapper`` command is affected by this flag, allowing the + use of :command:`glomap` if installed. Defaults to ``colmap``. + """ images_per_equirect: Literal[8, 14] = 8 """Number of samples per image to take from each equirectangular image. Used only when camera-type is equirectangular. diff --git a/nerfstudio/process_data/colmap_utils.py b/nerfstudio/process_data/colmap_utils.py index 38d9acdd35..a4664c5bc5 100644 --- a/nerfstudio/process_data/colmap_utils.py +++ b/nerfstudio/process_data/colmap_utils.py @@ -113,7 +113,8 @@ def run_colmap( matching_method: Matching method to use. refine_intrinsics: If True, refine intrinsics. colmap_cmd: Path to the COLMAP executable for feature extraction and matching. - mapper: Binary to use for the mapping stage ("colmap" or "glomap"). + mapper: Binary used only for the mapping stage. Set to ``glomap`` to call + :command:`glomap` instead of :command:`colmap`. """ colmap_version = get_colmap_version(colmap_cmd) From f14d0153992feae7ef2a4a096736bcd7999e8e10 Mon Sep 17 00:00:00 2001 From: igarzonpres Date: Thu, 5 Jun 2025 11:14:28 +0200 Subject: [PATCH 3/3] Docs: mention new SIFT options --- docs/quickstart/custom_dataset.md | 1 + .../process_data/colmap_converter_to_nerfstudio_dataset.py | 6 ++++++ nerfstudio/process_data/colmap_utils.py | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/docs/quickstart/custom_dataset.md b/docs/quickstart/custom_dataset.md index 7453ccb5b2..455a55d618 100644 --- a/docs/quickstart/custom_dataset.md +++ b/docs/quickstart/custom_dataset.md @@ -42,6 +42,7 @@ To assist running on custom data we have a script that will process a video or f ```bash ns-process-data {images, video} --data {DATA_PATH} --output-dir {PROCESSED_DATA_DIR} ``` +Advanced SIFT feature extraction options such as `--estimate-affine-shape` and `--domain-size-pooling` can also be passed to `ns-process-data` if desired. ### Training on your data diff --git a/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py b/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py index e8c903097f..281a8487ae 100644 --- a/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py +++ b/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py @@ -106,6 +106,10 @@ class ColmapConverterToNerfstudioDataset(BaseConverterToNerfstudioDataset): use_single_camera_mode: bool = True """Whether to assume all images taken with the same camera characteristics, set to False for multiple cameras in colmap (only works with hloc sfm_tool). """ + estimate_affine_shape: bool = False + """If True, enable affine shape estimation during SIFT feature extraction.""" + domain_size_pooling: bool = False + """If True, enable domain size pooling during SIFT feature extraction.""" @staticmethod def default_colmap_path() -> Path: @@ -222,6 +226,8 @@ def _run_colmap(self, mask_path: Optional[Path] = None): refine_intrinsics=self.refine_intrinsics, colmap_cmd=self.colmap_cmd, mapper=self.mapper, + estimate_affine_shape=self.estimate_affine_shape, + domain_size_pooling=self.domain_size_pooling, ) elif sfm_tool == "hloc": if mask_path is not None: diff --git a/nerfstudio/process_data/colmap_utils.py b/nerfstudio/process_data/colmap_utils.py index 38d9acdd35..abfad40046 100644 --- a/nerfstudio/process_data/colmap_utils.py +++ b/nerfstudio/process_data/colmap_utils.py @@ -100,6 +100,8 @@ def run_colmap( refine_intrinsics: bool = True, colmap_cmd: str = "colmap", mapper: Literal["colmap", "glomap"] = "colmap", + estimate_affine_shape: bool = False, + domain_size_pooling: bool = False, ) -> None: """Runs COLMAP on the images. @@ -114,6 +116,8 @@ def run_colmap( refine_intrinsics: If True, refine intrinsics. colmap_cmd: Path to the COLMAP executable for feature extraction and matching. mapper: Binary to use for the mapping stage ("colmap" or "glomap"). + estimate_affine_shape: If True, enable affine shape estimation for SIFT. + domain_size_pooling: If True, enable domain size pooling for SIFT. """ colmap_version = get_colmap_version(colmap_cmd) @@ -129,6 +133,8 @@ def run_colmap( "--ImageReader.single_camera 1", f"--ImageReader.camera_model {camera_model.value}", f"--SiftExtraction.use_gpu {int(gpu)}", + f"--SiftExtraction.estimate_affine_shape {int(estimate_affine_shape)}", + f"--SiftExtraction.domain_size_pooling {int(domain_size_pooling)}", ] if camera_mask_path is not None: feature_extractor_cmd.append(f"--ImageReader.camera_mask_path {camera_mask_path}")