Skip to content

Instantly share code, notes, and snippets.

@vincentfretin
Last active September 27, 2025 14:35
Show Gist options
  • Select an option

  • Save vincentfretin/ca55b750d7be907c3fd74557a006db97 to your computer and use it in GitHub Desktop.

Select an option

Save vincentfretin/ca55b750d7be907c3fd74557a006db97 to your computer and use it in GitHub Desktop.
# Elapsed time comments correspond to a 842 images dataset taken with a Pixel 9 Pro phone.
# ~~~~ variables ~~~~
INPUT_PATH=~/gaussiansplats_images/park2
OUTPUTDIR=~/gaussiansplats/park2
CHECKPOINTDIR=/tmp
# ~~~~ extract video frames from a flat video in LOG color profile and using rawtherapee-cli to change the colors ~~~~
# cd $INPUT_PATH
# mkdir -p extracted_images images
# ffmpeg -i PRO_VID_20240201_022335_10_001_converted.mp4 -qscale:v 1 -qmin 1 -vf "fps=2" extracted_images/frame_%04d.jpg
# cd extracted_images
# for file in *.jpg; do rawtherapee-cli -O ../images/$file -s -p ../../standard_iso_high.pp3 -j100 -Y -c $file; done
# if you did a flat video in default vivid color profile, no need for rawtherapee-cli, extract directly in images directory
# cd $INPUT_PATH
# mkdir -p images
# ffmpeg -i PRO_VID_20240201_022335_10_001_converted.mp4 -qscale:v 1 -qmin 1 -vf "fps=2" images/frame_%04d.jpg
# Select the sharpest frames
# You can use https://github.com/SharkWipf/nerf_dataset_preprocessing_helper to select the best frames from a video.
# There is a web (very slow to extract frames) and Windows app of a similar tool where you can specify the video start and end: https://sharp-frames.reflct.app/
# git clone [email protected]:SharkWipf/nerf_dataset_preprocessing_helper.git
# python ~/nerf_dataset_preprocessing_helper/01_filter_raw_data.py --input_path PRO_VID_20240201_022335_10_001_converted.mp4 --output_path ./images --target_count 240
# to get kind of 4fps for 1 min video with the sharpest images.
# ~~~~ create masks of persons and person shadows ~~~~
# create manually some black and white masks with gimp in indexed grayscale png with the same filename (without extension) + .png as the image in image directory
# black is the part you want to remove, the masks directory is used by brush automatically
# TODO auto create masks with sam2/yolo https://discord.com/channels/1293599119989805087/1299406262399926337/1405541656069144596
# https://docs.ultralytics.com/models/sam-2/
# ~~~~ copy images directory to destination ~~~~
#mkdir -p $OUTPUTDIR/images
#cp -rf $INPUT_PATH/images/*.jpg $OUTPUTDIR/images/
#cp -rf $INPUT_PATH/masks $OUTPUTDIR/
# Use symbolic links to avoid copying all the images
mkdir -p $OUTPUTDIR
ln -s $INPUT_PATH/images $OUTPUTDIR/images
if [ -e "$INPUT_PATH/masks" ]; then ln -s $INPUT_PATH/masks $OUTPUTDIR/masks; fi
# ~~~~ remove previous colmap data ~~~~
rm -rf $OUTPUTDIR/database.db $OUTPUTDIR/sparse
# ~~~~ restore to a checkpoint ~~~~
# cp -rf $CHECKPOINTDIR/matcher/* $OUTPUTDIR/
# ~~~~ feature extractor ~~~~
# colmap feature_extractor -h 2>&1|grep gpu
# --SiftExtraction.use_gpu arg (=1)
colmap feature_extractor --image_path $OUTPUTDIR/images --database_path $OUTPUTDIR/database.db --ImageReader.single_camera_per_folder 1 --ImageReader.camera_model PINHOLE
# --SiftExtraction.max_num_features 768
# --ImageReader.camera_model SIMPLE_RADIAL # that's the default
# --ImageReader.camera_model OPENCV_FISHEYE # if you use fisheye images
# Some folks on discord used fisheye photos and calibrated the camera with opencv and so is using --ImageReader.camera_model OPENCV
# https://colmap.github.io/cameras.html
# If using something other than PINHOLE, you need to undistort the images (see below) before training with brush.
# Thanks ichsan2895 for all the colmap commands and learning about the colmap image_undistorter command https://discord.com/channels/1293599119989805087/1293599547624263692/1362593181039988776
# Thanks ichsan2895 for --ImageReader.single_camera_per_folder 1 https://discord.com/channels/1293599119989805087/1299406262399926337/1315680611364769812
#
# Those options are good if you use sequential_matcher and you have issues getting matches because not enough features:
# --SiftExtraction.estimate_affine_shape=true --SiftExtraction.domain_size_pooling=true
# but those prevent using the GPU and will use only the CPU
# Thanks to https://github.com/NVlabs/instant-ngp/blob/master/scripts/colmap2nerf.py#L123 https://colmap.github.io/faq.html#increase-number-of-matches-sparse-3d-points
# Elapsed time: 1.133 [minutes]
# Elapsed time: 20.477 [minutes] with --SiftExtraction.estimate_affine_shape=true --SiftExtraction.domain_size_pooling=true or with explicit --SiftExtraction.use_gpu 0
mkdir -p $CHECKPOINTDIR/colmap_feature
cp -rf $OUTPUTDIR/database.db $CHECKPOINTDIR/colmap_feature/
# ~~~~ matcher ~~~~
# sequential_matcher is particularly good and quick if you extracted frames from a flat video, but exhaustive_matcher may give you better camera poses
# colmap sequential_matcher --database_path $OUTPUTDIR/database.db
# Elapsed time: 0.845 [minutes]
# with loop detection, documented in https://colmap.github.io/tutorial.html#feature-matching-and-geometric-verification
# colmap sequential_matcher --database_path $OUTPUTDIR/database.db --SequentialMatching.loop_detection 1
# Elapsed time: 3.201 [minutes]
# colmap exhaustive_matcher -h 2>&1|grep gpu
# --SiftMatching.use_gpu arg (=1)
colmap exhaustive_matcher --database_path $OUTPUTDIR/database.db
# Elapsed time: 37.964 [minutes]
mkdir -p $CHECKPOINTDIR/colmap_matcher
cp -rf $OUTPUTDIR/database.db $CHECKPOINTDIR/colmap_matcher/
# ~~~~ colmap mapper ~~~~
# colmap mapper -h 2>&1|grep gpu
# --Mapper.ba_use_gpu arg (=0)
mkdir $OUTPUTDIR/sparse && colmap mapper --database_path $OUTPUTDIR/database.db --image_path $OUTPUTDIR/images --output_path $OUTPUTDIR/sparse --Mapper.ba_use_gpu 1
# Elapsed time: 15.591 [minutes] with --Mapper.ba_use_gpu, but I got also almost the same without it
# colmap bundle_adjuster -h 2>&1|grep gpu
# --BundleAdjustment.use_gpu arg (=0)
colmap bundle_adjuster --input_path $OUTPUTDIR/sparse/0 --output_path $OUTPUTDIR/sparse/0 --BundleAdjustment.refine_principal_point 1 --BundleAdjustment.use_gpu 1
# Elapsed time: 0.883 [minutes] without --BundleAdjustment.use_gpu
# Elapsed time: 0.843 [minutes] with --BundleAdjustment.use_gpu
mkdir -p $CHECKPOINTDIR/colmap_mapper
cp -rf $OUTPUTDIR/database.db $OUTPUTDIR/sparse $CHECKPOINTDIR/colmap_mapper/
#
# OR
#
# ~~~~ glomap mapper ~~~~
# glomap mapper -h|grep gpu
# --GlobalPositioning.use_gpu arg (=1)
# --BundleAdjustment.use_gpu arg (=1)
# time glomap mapper --database_path $OUTPUTDIR/database.db --image_path $OUTPUTDIR/images --output_path $OUTPUTDIR/sparse --GlobalPositioning.use_gpu 0 --BundleAdjustment.use_gpu 0
# real 7m26,185s
# time glomap mapper --database_path $OUTPUTDIR/database.db --image_path $OUTPUTDIR/images --output_path $OUTPUTDIR/sparse --GlobalPositioning.use_gpu 1 --BundleAdjustment.use_gpu 1
# real 5m57,777s
# I don't quite get the same result than with colmap mapper, my newest glomap build may be bad, I had good results with a previous glomap build if I remember.
# mkdir -p $CHECKPOINTDIR/glomap_mapper
# cp -rf $OUTPUTDIR/database.db $OUTPUTDIR/sparse $CHECKPOINTDIR/glomap_mapper/
# ~~~~ check results ~~~~
# colmap gui --image_path $OUTPUTDIR/images --database_path $OUTPUTDIR/database.db --import_path $OUTPUTDIR/sparse/0
#
# You can also create a ply like this if you want to open it in blender for example:
# colmap model_converter --input_path "$OUTPUTDIR/sparse/0" --output_path "$OUTPUTDIR/sparse/0/sparse.ply" --output_type PLY
# ~~~~ undistort images (if --ImageReader.camera_model is different than PINHOLE) ~~~~
# be sure to remove previous run, otherwise you get an error that the images already exists and you end up with 2 images in undistorted/sparse although you have the images in undistorted/images
# rm -rf $OUTPUTDIR/undistorted
# colmap image_undistorter --image_path $OUTPUTDIR/images --input_path $OUTPUTDIR/sparse/0 --output_path $OUTPUTDIR/undistorted --output_type COLMAP
# ~~~~ brush training ~~~~
cd ~/brush
git checkout 5f79079a0e7ab4af452f1a2d4e38bb7a160aab2f # Sep 21, 2025
cargo run --release -- --export-path ${OUTPUTDIR}_results --sh-degree 0 --with-viewer --total-steps 60000 --max-splats 7000000 --max-resolution 2016 --growth-select-fraction 0.2 --growth-stop-iter 30000 $OUTPUTDIR
# use $OUTPUTDIR/undistorted instead of $OUTPUTDIR at the last argument in the above command if you did the colmap image_undistorter step
# Training took 2h 2m
# ~~~~ check splats results ~~~~
# Drag and drop ${OUTPUTDIR}_results/export_50000.ply to
# https://superspl.at/editor
# You can remove the previous export_??.ply to free up space
@ichsan2895
Copy link

Amazing code.
THANK YOU :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment