Last active
September 27, 2025 14:35
-
-
Save vincentfretin/ca55b750d7be907c3fd74557a006db97 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Amazing code.
THANK YOU :)