Skip to content
Snippets Groups Projects
Commit c9cd243c authored by Thomas Müller's avatar Thomas Müller
Browse files

`colmap2nerf.py`: download COLMAP and FFmpeg automatically on Windows

parent 0f7f245c
No related branches found
No related tags found
No related merge requests found
/.vscode
/.vs
/build*
/external
/figures
/out
/results
......
......@@ -3,6 +3,8 @@
Our NeRF implementation expects initial camera parameters to be provided in a `transforms.json` file in a format compatible with [the original NeRF codebase](https://www.matthewtancik.com/nerf).
We provide a script as a convenience, [scripts/colmap2nerf.py](/scripts/colmap2nerf.py), that can be used to process a video file or sequence of images, using the open source [COLMAP](https://colmap.github.io/) structure from motion software to extract the necessary camera data.
If you are using Windows, you do not need to install COLMAP yourself; running [scripts/colmap2nerf.py](/scripts/colmap2nerf.py) will automatically download COLMAP for you.
The training process can be quite picky about the dataset.
For example, it is important for the dataset to have good coverage, to not contain mislabelled camera data, and to not contain blurry frames (motion blur and defocus blur are both problematic).
This document attempts to give a few tips.
......@@ -57,9 +59,11 @@ To train on self-captured data, one has to process the data into an existing for
### COLMAP
Make sure that you have installed [COLMAP](https://colmap.github.io/) and that it is available in your PATH. If you are using a video file as input, also be sure to install [FFmpeg](https://www.ffmpeg.org/) and make sure that it is available in your PATH.
If you use Linux, make sure that you have installed [COLMAP](https://colmap.github.io/) and that it is available in your PATH. If you are using a video file as input, also be sure to install [FFmpeg](https://www.ffmpeg.org/) and make sure that it is available in your PATH.
To check that this is the case, from a terminal window, you should be able to run `colmap` and `ffmpeg -?` and see some help text from each.
If you use Windows, you do not need to install anything. COLMAP and FFmpeg will be downloaded automatically when running the following scripts.
If you are training from a video file, run the [scripts/colmap2nerf.py](/scripts/colmap2nerf.py) script from the folder containing the video, with the following recommended parameters:
```sh
......@@ -74,7 +78,7 @@ For training from images, place them in a subfolder called `images` and then use
data-folder$ python [path-to-instant-ngp]/scripts/colmap2nerf.py --colmap_matcher exhaustive --run_colmap --aabb_scale 16
```
The script will run FFmpeg and/or COLMAP as needed, followed by a conversion step to the required `transforms.json` format, which will be written in the current directory.
The script will run (and install, if you use Windows) FFmpeg and COLMAP as needed, followed by a conversion step to the required `transforms.json` format, which will be written in the current directory.
By default, the script invokes colmap with the "sequential matcher", which is suitable for images taken from a smoothly changing camera path, as in a video. The exhaustive matcher is more appropriate if the images are in no particular order, as shown in the image example above.
For more options, you can run the script with `--help`. For more advanced uses of COLMAP or for challenging scenes, please see the [COLMAP documentation](https://colmap.github.io/cli.html); you may need to modify the [scripts/colmap2nerf.py](/scripts/colmap2nerf.py) script itself.
......
......@@ -9,6 +9,7 @@
# license agreement from NVIDIA CORPORATION is strictly prohibited.
import argparse
from glob import glob
import os
from pathlib import Path, PurePosixPath
......@@ -20,6 +21,9 @@ import cv2
import os
import shutil
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
SCRIPTS_FOLDER = os.path.join(ROOT_DIR, "scripts")
def parse_args():
parser = argparse.ArgumentParser(description="Convert a text colmap export to nerf format transforms.json; optionally convert video to images, and optionally run colmap in the first place.")
......@@ -49,8 +53,21 @@ def do_system(arg):
sys.exit(err)
def run_ffmpeg(args):
ffmpeg_binary = "ffmpeg"
if os.name == 'nt':
ffmpeg_glob = os.path.join(ROOT_DIR, "external", "ffmpeg", "*", "bin", "ffmpeg.exe")
candidates = glob(ffmpeg_glob)
if not candidates:
print("FFmpeg not found. Attempting to download FFmpeg from the internet.")
do_system(os.path.join(SCRIPTS_FOLDER, "download_ffmpeg.bat"))
candidates = glob(ffmpeg_glob)
if candidates:
ffmpeg_binary = candidates[0]
if not os.path.isabs(args.images):
args.images = os.path.join(os.path.dirname(args.video_in), args.images)
images = "\"" + args.images + "\""
video = "\"" + args.video_in + "\""
fps = float(args.video_fps) or 1.0
......@@ -69,9 +86,21 @@ def run_ffmpeg(args):
if time_slice:
start, end = time_slice.split(",")
time_slice_value = f",select='between(t\,{start}\,{end})'"
do_system(f"ffmpeg -i {video} -qscale:v 1 -qmin 1 -vf \"fps={fps}{time_slice_value}\" {images}/%04d.jpg")
do_system(f"{ffmpeg_binary} -i {video} -qscale:v 1 -qmin 1 -vf \"fps={fps}{time_slice_value}\" {images}/%04d.jpg")
def run_colmap(args):
colmap_binary = "colmap"
if os.name == 'nt':
colmap_glob = os.path.join(ROOT_DIR, "external", "colmap", "*", "COLMAP.bat")
candidates = glob(colmap_glob)
if not candidates:
print("COLMAP not found. Attempting to download COLMAP from the internet.")
do_system(os.path.join(SCRIPTS_FOLDER, "download_colmap.bat"))
candidates = glob(colmap_glob)
if candidates:
colmap_binary = candidates[0]
db = args.colmap_db
images = "\"" + args.images + "\""
db_noext=str(Path(db).with_suffix(""))
......@@ -85,8 +114,8 @@ def run_colmap(args):
sys.exit(1)
if os.path.exists(db):
os.remove(db)
do_system(f"colmap feature_extractor --ImageReader.camera_model {args.colmap_camera_model} --ImageReader.camera_params \"{args.colmap_camera_params}\" --SiftExtraction.estimate_affine_shape=true --SiftExtraction.domain_size_pooling=true --ImageReader.single_camera 1 --database_path {db} --image_path {images}")
match_cmd = f"colmap {args.colmap_matcher}_matcher --SiftMatching.guided_matching=true --database_path {db}"
do_system(f"{colmap_binary} feature_extractor --ImageReader.camera_model {args.colmap_camera_model} --ImageReader.camera_params \"{args.colmap_camera_params}\" --SiftExtraction.estimate_affine_shape=true --SiftExtraction.domain_size_pooling=true --ImageReader.single_camera 1 --database_path {db} --image_path {images}")
match_cmd = f"{colmap_binary} {args.colmap_matcher}_matcher --SiftMatching.guided_matching=true --database_path {db}"
if args.vocab_path:
match_cmd += f" --VocabTreeMatching.vocab_tree_path {args.vocab_path}"
do_system(match_cmd)
......@@ -95,14 +124,14 @@ def run_colmap(args):
except:
pass
do_system(f"mkdir {sparse}")
do_system(f"colmap mapper --database_path {db} --image_path {images} --output_path {sparse}")
do_system(f"colmap bundle_adjuster --input_path {sparse}/0 --output_path {sparse}/0 --BundleAdjustment.refine_principal_point 1")
do_system(f"{colmap_binary} mapper --database_path {db} --image_path {images} --output_path {sparse}")
do_system(f"{colmap_binary} bundle_adjuster --input_path {sparse}/0 --output_path {sparse}/0 --BundleAdjustment.refine_principal_point 1")
try:
shutil.rmtree(text)
except:
pass
do_system(f"mkdir {text}")
do_system(f"colmap model_converter --input_path {sparse}/0 --output_path {text} --output_type TXT")
do_system(f"{colmap_binary} model_converter --input_path {sparse}/0 --output_path {text} --output_type TXT")
def variance_of_laplacian(image):
return cv2.Laplacian(image, cv2.CV_64F).var()
......
@echo off
set cwd=%cd%
cd /D %~dp0
echo Downloading COLMAP...
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://github.com/colmap/colmap/releases/download/3.7/COLMAP-3.7-windows-no-cuda.zip', 'colmap.zip')"
echo Unzipping...
powershell Expand-Archive colmap.zip -DestinationPath ..\external\colmap -Force
echo Cleaning up...
if exist colmap.zip del /f /q colmap.zip
exit /b
@echo off
set cwd=%cd%
cd /D %~dp0
echo Downloading FFmpeg...
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://github.com/GyanD/codexffmpeg/releases/download/5.1.2/ffmpeg-5.1.2-full_build.zip', 'ffmpeg.zip')"
echo Unzipping...
powershell Expand-Archive ffmpeg.zip -DestinationPath ..\external\ffmpeg -Force
echo Cleaning up...
if exist ffmpeg.zip del /f /q ffmpeg.zip
exit /b
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment