diff --git a/docs/tutorials/data/creating_dataset.md b/docs/tutorials/data/creating_dataset.md index 89719f92c..b3fefe516 100644 --- a/docs/tutorials/data/creating_dataset.md +++ b/docs/tutorials/data/creating_dataset.md @@ -32,8 +32,11 @@ python scripts/run_train.py instant-ngp nerfactory --pipeline.datamanager.datapa The COLMAP maintainers recommend using VCPKG to install COLAMP. If the following command do not work, please refer to the [COLMAP installation guide](https://colmap.github.io/install.html) for additional installation methods. +::::::{tab-set} +:::::{tab-item} Linux + ::::{tab-set} -:::{tab-item} Linux +:::{tab-item} CUDA ```bash git clone https://github.com/microsoft/vcpkg @@ -43,19 +46,35 @@ cd vcpkg ``` ::: - -:::{tab-item} OSX +:::{tab-item} CPU ```bash git clone https://github.com/microsoft/vcpkg cd vcpkg ./bootstrap-vcpkg.sh -./vcpkg install colmap[cuda]:x64-osx +./vcpkg install colmap:x64-linux ``` ::: +:::: -:::{tab-item} Windows +::::: + +:::::{tab-item} OSX + +```bash +git clone https://github.com/microsoft/vcpkg +cd vcpkg +./bootstrap-vcpkg.sh +./vcpkg install colmap +``` + +::::: + +:::::{tab-item} Windows + +::::{tab-set} +:::{tab-item} CUDA ```bash git clone https://github.com/microsoft/vcpkg @@ -64,5 +83,18 @@ cd vcpkg ./vcpkg install colmap[cuda]:x64-windows ``` +::: +:::{tab-item} CPU + +```bash +git clone https://github.com/microsoft/vcpkg +cd vcpkg +./bootstrap-vcpkg.sh +./vcpkg install colmap:x64-windows +``` + ::: :::: + +::::: +:::::: diff --git a/pyproject.toml b/pyproject.toml index 91d0561a5..cdfca6213 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ classifiers = [ dependencies = [ "aiohttp==3.8.1", "aiortc==1.3.2", + "appdirs>=1.4", "av==9.2.0", "dcargs>=0.3.9", "gdown==4.5.1", @@ -36,6 +37,7 @@ dependencies = [ "plotly==5.7.0", "protobuf==3.20.0", "python-socketio==5.7.1", + "requests", "rich==12.5.1", "tensorboard==2.9.0", "torch==1.12.1", diff --git a/scripts/process_data.py b/scripts/process_data.py index f9d6ebffc..e5df5b3b1 100755 --- a/scripts/process_data.py +++ b/scripts/process_data.py @@ -9,9 +9,12 @@ from enum import Enum from pathlib import Path from typing import Literal, Optional, Tuple +import appdirs import dcargs import numpy as np +import requests from rich.console import Console +from rich.progress import track from nerfactory.utils import colmap_utils @@ -69,6 +72,31 @@ def get_colmap_version(default_version=3.8) -> float: return default_version +def get_vocab_tree() -> Path: + """Return path to vocab tree. Downloads vocab tree if it doesn't exist. + + Returns: + The path to the vocab tree. + """ + vocab_tree_filename = Path(appdirs.user_data_dir("nerfactory")) / "vocab_tree.fbow" + + if not vocab_tree_filename.exists(): + r = requests.get("https://demuc.de/colmap/vocab_tree_flickr100K_words32K.bin", 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") + assert total_length is not None + for chunk in track( + r.iter_content(chunk_size=1024), + total=int(total_length) / 1024 + 1, + description="Downloading vocab tree...", + ): + if chunk: + f.write(chunk) + f.flush() + return vocab_tree_filename + + def run_command(cmd, verbose=False) -> Optional[str]: """Runs a command and returns the output. @@ -190,6 +218,7 @@ def run_colmap( camera_model: CameraModel, gpu: bool = True, verbose: bool = False, + matching_method: Literal["vocab_tree", "exhaustive", "sequential"] = "vocab_tree", ) -> None: """Runs COLMAP on the images. @@ -224,10 +253,13 @@ def run_colmap( # Feature matching feature_matcher_cmd = [ - "colmap exhaustive_matcher", + f"colmap {matching_method}_matcher", f"--database_path {colmap_dir / 'database.db'}", f"--SiftMatching.use_gpu {int(gpu)}", ] + if matching_method == "vocab_tree": + vocab_tree_filename = get_vocab_tree() + feature_matcher_cmd.append(f"--VocabTreeMatching.vocab_tree_path {vocab_tree_filename}") feature_matcher_cmd = " ".join(feature_matcher_cmd) if not verbose: with CONSOLE.status("[bold yellow]Running COLMAP feature matcher...", spinner="runner"): @@ -342,6 +374,7 @@ def main( output_dir: Path, num_frames_target: int = 300, camera_type: Literal["perspective", "fisheye"] = "perspective", + matching_method: Literal["exhaustive", "sequential", "vocab_tree"] = "vocab_tree", num_downscales: int = 3, skip_colmap: bool = False, gpu: bool = True, @@ -361,6 +394,8 @@ def main( output_dir: Path to the output directory. num_frames: Target number of frames to use for the dataset, results may not be exact. camera_type: Camera model to use. + matching_method: Feature matching method to use. Vocab tree is recommended for a balance of speed and + accuracy. Exhaustive is slower but more accurate. Sequential is faster but should only be used for videos. num_downscales: Number of times to downscale the images. Downscales by 2 each time. For example a value of 3 will downscale the images by 2x, 4x, and 8x. skip_colmap: If True, skips COLMAP and generates transforms.json if possible. @@ -419,7 +454,14 @@ def main( if not skip_colmap: colmap_dir.mkdir(parents=True, exist_ok=True) - run_colmap(image_dir=image_dir, colmap_dir=colmap_dir, camera_model=camera_model, gpu=gpu, verbose=verbose) + run_colmap( + image_dir=image_dir, + colmap_dir=colmap_dir, + camera_model=camera_model, + gpu=gpu, + verbose=verbose, + matching_method=matching_method, + ) if (colmap_dir / "sparse" / "0" / "cameras.bin").exists(): with CONSOLE.status("[bold yellow]Saving results to transforms.json", spinner="balloon"):