Skip to content

Instantly share code, notes, and snippets.

@polyfjord
Created August 3, 2025 10:51
Show Gist options
  • Select an option

  • Save polyfjord/4ed7e8988bdb9674145f1c270440200d to your computer and use it in GitHub Desktop.

Select an option

Save polyfjord/4ed7e8988bdb9674145f1c270440200d to your computer and use it in GitHub Desktop.
Batch script for automated photogrammetry tracking workflow
:: ================================================================
:: BATCH SCRIPT FOR AUTOMATED PHOTOGRAMMETRY TRACKING WORKFLOW
:: By polyfjord - https://youtube.com/polyfjord
:: ================================================================
:: USAGE
:: • Double-click this .bat or run it from a command prompt.
:: • Frames are extracted, features matched, and a sparse
:: reconstruction is produced automatically.
:: • Videos that have already been processed are skipped on
:: subsequent runs.
::
:: PURPOSE
:: This is a fully automated photogrammetry tracker for turning
:: videos into COLMAP sparse models with robust error handling,
:: clean directory setup, and clear ✖ / ✔ logging.
::
:: FOLDER LAYOUT (all folders sit side-by-side):
:: 01 COLMAP – Download the latest release from
:: https://github.com/colmap/colmap
:: and place colmap.bat (plus its dlls) here.
::
:: 02 VIDEOS – Put your input video files (.mp4, .mov, …) here.
:: All framerates and aspect ratios are supported.
::
:: 03 FFMPEG – Drop a **static build** of FFmpeg
:: (either ffmpeg.exe or bin\ffmpeg.exe) here.
::
:: 04 SCENES – The script creates one sub-folder per video
:: containing extracted frames, the COLMAP
:: database, sparse model, and TXT export.
::
:: 05 SCRIPTS – This batch file lives here.
::
:: ================================================================
@echo off
:: ---------- Resolve top-level folder (one up from this .bat) -----
pushd "%~dp0\.." >nul
set "TOP=%cd%"
popd >nul
:: ---------- Key paths -------------------------------------------
set "COLMAP_DIR=%TOP%\01 COLMAP"
set "VIDEOS_DIR=%TOP%\02 VIDEOS"
set "FFMPEG_DIR=%TOP%\03 FFMPEG"
set "SCENES_DIR=%TOP%\04 SCENES"
:: ---------- Locate ffmpeg.exe -----------------------------------
if exist "%FFMPEG_DIR%\ffmpeg.exe" (
set "FFMPEG=%FFMPEG_DIR%\ffmpeg.exe"
) else if exist "%FFMPEG_DIR%\bin\ffmpeg.exe" (
set "FFMPEG=%FFMPEG_DIR%\bin\ffmpeg.exe"
) else (
echo [ERROR] ffmpeg.exe not found inside "%FFMPEG_DIR%".
pause & goto :eof
)
:: ---------- Locate colmap.exe (skip the .bat) --------------------
if exist "%COLMAP_DIR%\colmap.exe" (
set "COLMAP=%COLMAP_DIR%\colmap.exe"
) else if exist "%COLMAP_DIR%\bin\colmap.exe" (
set "COLMAP=%COLMAP_DIR%\bin\colmap.exe"
) else (
echo [ERROR] colmap.exe not found inside "%COLMAP_DIR%".
pause & goto :eof
)
:: ---------- Put COLMAP’s dll folder(s) on PATH -------------------
set "PATH=%COLMAP_DIR%;%COLMAP_DIR%\bin;%PATH%"
:: ---------- Ensure required folders exist ------------------------
if not exist "%VIDEOS_DIR%" (
echo [ERROR] Input folder "%VIDEOS_DIR%" missing.
pause & goto :eof
)
if not exist "%SCENES_DIR%" mkdir "%SCENES_DIR%"
:: ---------- Count videos for progress bar ------------------------
for /f %%C in ('dir /b /a-d "%VIDEOS_DIR%\*" ^| find /c /v ""') do set "TOTAL=%%C"
if "%TOTAL%"=="0" (
echo [INFO] No video files found in "%VIDEOS_DIR%".
pause & goto :eof
)
echo ==============================================================
echo Starting COLMAP on %TOTAL% video(s) …
echo ==============================================================
setlocal EnableDelayedExpansion
set /a IDX=0
for %%V in ("%VIDEOS_DIR%\*.*") do (
if exist "%%~fV" (
set /a IDX+=1
call :PROCESS_VIDEO "%%~fV" "!IDX!" "%TOTAL%"
)
)
echo --------------------------------------------------------------
echo All jobs finished – results are in "%SCENES_DIR%".
echo --------------------------------------------------------------
pause
goto :eof
:PROCESS_VIDEO
:: ----------------------------------------------------------------
:: %1 = full path to video %2 = current index %3 = total
:: ----------------------------------------------------------------
setlocal
set "VIDEO=%~1"
set "NUM=%~2"
set "TOT=%~3"
for %%I in ("%VIDEO%") do (
set "BASE=%%~nI"
set "EXT=%%~xI"
)
echo.
echo [!NUM!/!TOT!] === Processing "!BASE!!EXT!" ===
:: -------- Directory layout for this scene -----------------------
set "SCENE=%SCENES_DIR%\!BASE!"
set "IMG_DIR=!SCENE!\images"
set "SPARSE_DIR=!SCENE!\sparse"
:: -------- Skip if already reconstructed -------------------------
if exist "!SCENE!" (
echo ↻ Skipping "!BASE!" – already reconstructed.
goto :END
)
:: Clean slate ----------------------------------------------------
mkdir "!IMG_DIR!" >nul
mkdir "!SPARSE_DIR!" >nul
:: -------- 1) Extract every frame --------------------------------
echo [1/4] Extracting frames …
"%FFMPEG%" -loglevel error -stats -i "!VIDEO!" -qscale:v 2 ^
"!IMG_DIR!\frame_%%06d.jpg"
if errorlevel 1 (
echo ✖ FFmpeg failed – skipping "!BASE!".
goto :END
)
:: Check at least one frame exists
dir /b "!IMG_DIR!\*.jpg" >nul 2>&1 || (
echo ✖ No frames extracted – skipping "!BASE!".
goto :END
)
:: -------- 2) Feature extraction ---------------------------------
echo [2/4] COLMAP feature_extractor …
"%COLMAP%" feature_extractor ^
--database_path "!SCENE!\database.db" ^
--image_path "!IMG_DIR!" ^
--ImageReader.single_camera 1 ^
--SiftExtraction.use_gpu 1 ^
--SiftExtraction.max_image_size 4096
if errorlevel 1 (
echo ✖ feature_extractor failed – skipping "!BASE!".
goto :END
)
:: -------- 3) Sequential matching --------------------------------
echo [3/4] COLMAP sequential_matcher …
"%COLMAP%" sequential_matcher ^
--database_path "!SCENE!\database.db" ^
--SequentialMatching.overlap 15
if errorlevel 1 (
echo ✖ sequential_matcher failed – skipping "!BASE!".
goto :END
)
:: -------- 4) Sparse reconstruction ------------------------------
echo [4/4] COLMAP mapper …
"%COLMAP%" mapper ^
--database_path "!SCENE!\database.db" ^
--image_path "!IMG_DIR!" ^
--output_path "!SPARSE_DIR!" ^
--Mapper.num_threads %NUMBER_OF_PROCESSORS%
if errorlevel 1 (
echo ✖ mapper failed – skipping "!BASE!".
goto :END
)
:: -------- Export best model to TXT ------------------------------
if exist "!SPARSE_DIR!\0" (
"%COLMAP%" model_converter ^
--input_path "!SPARSE_DIR!\0" ^
--output_path "!SPARSE_DIR!" ^
--output_type TXT >nul
)
echo ✔ Finished "!BASE!" (!NUM!/!TOT!)
:END
endlocal & goto :eof
@TheGreenG
Copy link
Copy Markdown

It seems that myself and others in the YouTube comment section have had a problem where after computation the sparse folder is empty. In my case, a roughly 15 GB database (.db) file was created after feature extraction and such but no .txt files or any information at all was created in the sparse folder.

Is there an obvious reason that I'm missing as to why there is no information in the sparse folder?

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