Skip to content

Instantly share code, notes, and snippets.

@Norgus
Forked from celestial-33/readme-mac.md
Last active September 4, 2025 01:32
Show Gist options
  • Save Norgus/9e877924949d778db12c534ff1bafe36 to your computer and use it in GitHub Desktop.
Save Norgus/9e877924949d778db12c534ff1bafe36 to your computer and use it in GitHub Desktop.
AutoTracker workflow using GLOMAP

Automated Video to 3D Scan Workflow (GLOMAP + COLMAP) for Linux

This repository contains a Bash script for automating a photogrammetry workflow on Linux using GLOMAP and COLMAP. It takes video files as input, extracts frames via FFmpeg, and generates a 3D sparse point cloud for each video.

This script is a Linux adaptation of celestial's Mac adaptation of Polyfjord’s workflow here, with minimul adaptations to run smoothly on Linux systems.


Features

  • One-Command Automation: Processes all videos in the input folder in a single run.
  • Error Handling: Skips already processed videos and ensures the workflow executes step by step without breaking.
  • Organized Output: Keeps results clean with a structured project folder.
  • COLMAP + GLOMAP Integration: Extracts features, performs sequential matching, and runs sparse reconstruction automatically.
  • TXT Export: Converts COLMAP models to TXT format for easier inspection or import.

Requirements

Software

  • COLMAP – Structure-from-motion and multi-view stereo pipeline.
  • GLOMAP – COLMAP extension for automated mapping.
  • FFmpeg – For frame extraction.

Folder Structure

    Project_Folder/
    ├── VIDEOS/      # Place input video files (.mp4, .mov) here.
    ├── SCENES/      # The script saves all outputs here.
    └── SCRIPTS/     # The run_glomap.sh script lives here.

How to Use

  1. Set Up Folders: Create the structure shown above.

  2. Add Videos: Copy your .mp4 or .mov files into the VIDEOS/ folder.

  3. Save the Script: Place the script (run_glomap.sh) in the SCRIPTS/ folder.

  4. Update Paths: Edit the script and update these variables to match your system installation (only necessary if they aren't already on $PATH):

    FFMPEG="$(which ffmpeg)"
    COLMAP="$(which colmap)"
    GLOMAP="$(which glomap)"
  5. Make it Executable:

    chmod +x run_glomap.sh
  6. Run the Script: From inside the SCRIPTS/ folder:

    ./run_glomap.sh

Troubleshooting

  • COLMAP/GLOMAP/FFmpeg not found: Ensure the paths in the script match your system installation.

  • No frames extracted: Check that your video files are valid and playable by FFmpeg.

  • Slow processing: Reduce --SiftExtraction.max_image_size (e.g., from 4096 → 2048) or process shorter clips.


Conclusion

This script fully automates Polyfjord’s photogrammetry workflow on macOS using GLOMAP and COLMAP, making it easy to generate 3D sparse point clouds from videos.

#!/usr/bin/env bash
# ================================================================
# BASH SCRIPT FOR AUTOMATED PHOTOGRAMMETRY TRACKING WORKFLOW (GLOMAP + COLMAP)
# for Linux!
# ================================================================
set -e # Stop on error
# --- Resolve top-level folder (one up from this script) ---
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
TOP="$(dirname "$SCRIPT_DIR")"
# --- Key paths ---
VIDEOS_DIR="$TOP/VIDEOS"
SCENES_DIR="$TOP/SCENES"
# --- System-wide executables ---
# replace with full paths to binaries if using one
# not on $PATH
FFMPEG="$(which ffmpeg)"
COLMAP="$(which colmap)"
GLOMAP="$(which glomap)"
# --- CPU thread count ---
NUM_THREADS=$(nproc)
# --- Ensure executables exist ---
for cmd in "$FFMPEG" "$COLMAP" "$GLOMAP"; do
if [ ! -x "$cmd" ]; then
echo "[ERROR] Executable not found: $cmd" >&2
exit 1
fi
done
# --- Ensure required folders exist ---
if [ ! -d "$VIDEOS_DIR" ]; then
echo "[ERROR] Input folder '$VIDEOS_DIR' missing." >&2
exit 1
fi
mkdir -p "$SCENES_DIR"
# --- Count videos ---
TOTAL=$(find "$VIDEOS_DIR" -maxdepth 1 -type f | wc -l | tr -d ' ')
if [ "$TOTAL" -eq 0 ]; then
echo "[INFO] No video files found in '$VIDEOS_DIR'."
exit 0
fi
echo "=============================================================="
echo " Starting GLOMAP pipeline on $TOTAL video(s) …"
echo "=============================================================="
IDX=0
for VIDEO_FILE in "$VIDEOS_DIR"/*; do
[ -f "$VIDEO_FILE" ] || continue
IDX=$((IDX + 1))
BASENAME=$(basename "$VIDEO_FILE")
BASE="${BASENAME%.*}"
echo
echo "[$IDX/$TOTAL] === Processing \"$BASENAME\" ==="
SCENE_DIR="$SCENES_DIR/$BASE"
IMG_DIR="$SCENE_DIR/images"
SPARSE_DIR="$SCENE_DIR/sparse"
# Skip if already reconstructed
if [ -d "$SCENE_DIR" ]; then
echo " • Skipping \"$BASE\" – already reconstructed."
continue
fi
# Create directories
mkdir -p "$IMG_DIR" "$SPARSE_DIR"
# --- 1) Extract frames ---
echo " [1/4] Extracting frames …"
"$FFMPEG" -loglevel error -stats -i "$VIDEO_FILE" -qscale:v 2 "$IMG_DIR/frame_%06d.png"
if ! ls "$IMG_DIR"/*.png &> /dev/null; then
echo " × No frames extracted – skipping \"$BASE\"."
rm -rf "$SCENE_DIR"
continue
fi
# --- 2) Feature extraction (COLMAP) ---
echo " [2/4] COLMAP feature_extractor …"
"$COLMAP" feature_extractor \
--database_path "$SCENE_DIR/database.db" \
--image_path "$IMG_DIR" \
--ImageReader.single_camera 1 \
--SiftExtraction.max_image_size 4096
# --- 3) Sequential matching (COLMAP) ---
echo " [3/4] COLMAP sequential_matcher …"
"$COLMAP" sequential_matcher \
--database_path "$SCENE_DIR/database.db" \
--SequentialMatching.overlap 15
# --- 4) Sparse reconstruction (GLOMAP) ---
echo " [4/4] GLOMAP mapper …"
"$GLOMAP" mapper \
--database_path "$SCENE_DIR/database.db" \
--image_path "$IMG_DIR" \
--output_path "$SPARSE_DIR"
# --- Export TXT inside model folder ---
if [ -d "$SPARSE_DIR/0" ]; then
"$COLMAP" model_converter \
--input_path "$SPARSE_DIR/0" \
--output_path "$SPARSE_DIR/0" \
--output_type TXT > /dev/null
"$COLMAP" model_converter \
--input_path "$SPARSE_DIR/0" \
--output_path "$SPARSE_DIR" \
--output_type TXT > /dev/null
fi
echo " ✓ Finished \"$BASE\" ($IDX/$TOTAL)"
done
echo "--------------------------------------------------------------"
echo " All jobs finished – results are in \"$SCENES_DIR\"."
echo "--------------------------------------------------------------"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment