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 55f657a3a4..17f7cae5b2 100644 --- a/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py +++ b/nerfstudio/process_data/colmap_converter_to_nerfstudio_dataset.py @@ -83,6 +83,12 @@ 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. + + 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. @@ -104,6 +110,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: @@ -219,6 +229,9 @@ 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, + estimate_affine_shape=self.estimate_affine_shape, + domain_size_pooling=self.domain_size_pooling, ) elif sfm_tool == "hloc": if mask_path is not None: @@ -245,6 +258,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..ba20250841 100644 --- a/nerfstudio/process_data/colmap_utils.py +++ b/nerfstudio/process_data/colmap_utils.py @@ -99,6 +99,9 @@ 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", + estimate_affine_shape: bool = False, + domain_size_pooling: bool = False, ) -> None: """Runs COLMAP on the images. @@ -111,7 +114,15 @@ 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. +<<<<<<< HEAD + mapper: Binary used only for the mapping stage. Set to ``glomap`` to call + :command:`glomap` instead of :command:`colmap`. +======= + 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. +>>>>>>> origin """ colmap_version = get_colmap_version(colmap_cmd) @@ -127,6 +138,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}") @@ -154,7 +167,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}",