Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DroneDatasetAnalyzer

A zero-dependency .NET CLI tool that analyzes DJI drone photo datasets. Extracts flight timelines, camera settings, overlap geometry, gimbal configuration, altitude/GSD, and terrain elevation from EXIF + XMP metadata.

Takes one or more directories of photos and produces a comprehensive mission report in seconds — no image processing, no external libraries, just raw metadata parsing.

Features

  • Capture Group Classification — Automatically groups flights by altitude band (stable-altitude flights clustered, varying-altitude flights in a catch-all group) with per-group analysis; preliminary relative-altitude bands are reconciled against measured AGL, merging bands that are the same capture plan flown over different terrain and labeling groups by AGL (relative altitude is indicative only)
  • Flight Timeline — Segments photos into flights by detecting power cycles (timestamp gaps + DJI sequence resets)
  • Camera Settings — Shutter speed, aperture, ISO, focal length per flight
  • Forward & Side Overlap — Computed from consecutive GPS positions and flight-line geometry, per capture group
  • Smart Oblique Analysis — Correlates gimbal pitch, roll, and yaw to determine the real oblique angle setting
  • GSD & Footprint — Ground sample distance and footprint from DJI calibrated focal length, computed from the measured height above ground (not the takeoff-relative altitude, which is wrong under terrain follow and on sloped sites)
  • Terrain Elevation & Datum-Correct AGL — Queries Open-Meteo SRTM API for ground elevation; resolves the DJI AbsoluteAltitude vertical datum (RTK platforms write WGS84 ellipsoidal heights, consumer platforms EGM96 MSL) and corrects with an embedded EGM96 geoid grid before computing AGL
  • Terrain-Follow Detection — Per capture group, detects when the takeoff-relative altitude tracks the terrain (slope ≈ 1 regression against SRTM ground elevation), flagging missions where relative altitude is not height above ground
  • Speed Profile — Ground-speed statistics (min/max/mean/median/percentiles) per capture group and mission-wide, densely sampled from the overlap block, with capture-cruise vs transit-leg regime split
  • Equipment ID — Drone model, serial numbers, sensor specs from XMP metadata
  • Per-Flight Breakdown — Day-by-day tables with photo counts, durations, camera parameters, and group labels
  • Multi-Directory Support — Merge photos from multiple folders (common when flights are split across subfolders)
  • Recursive Search — Automatically finds all JPEG files in subdirectories

Quick Start

# Clone and build
git clone https://github.com/Alos-no/DroneDatasetAnalyzer.git
cd DroneDatasetAnalyzer
dotnet build src/DroneDatasetAnalyzer.csproj

# Analyze a dataset (searches recursively)
dotnet run --project src/DroneDatasetAnalyzer.csproj -- "/path/to/drone/photos"

Or download a pre-built release from the Releases page:

DroneDatasetAnalyzer "/path/to/drone/photos"

Usage

DroneDatasetAnalyzer <directory> [directory2 ...] [options]

Arguments:
  <directory>                 One or more directories containing DJI drone photos.
                              Each directory is searched recursively for JPEG files.
                              Photos from all directories are merged and analyzed together.

Options:
  -o, --output <path>         Output report path (default: MISSION-REPORT.md in first dir)
  -s, --samples <n>           Samples per flight for metadata (default: 9)
  -b, --overlap-block <n>     Consecutive photos for overlap (default: 500)
  --skip-elevation            Skip elevation API query (faster, no AGL)
  --altitude-datum <mode>     AbsoluteAltitude datum: auto | ellipsoidal | msl (default: auto)
                              RTK-capable platforms (M4E, M3E, M300/350, P4RTK) write WGS84
                              ellipsoidal heights; consumer platforms write EGM96 MSL.
                              Auto detects via the RtkFlag XMP tag, with a relative-altitude
                              consistency heuristic as fallback.
  -h, --help                  Show help

Examples

# Analyze a dataset with photos in subfolders (common DJI folder structure)
DroneDatasetAnalyzer "D:\Flights\2026-05-03_Site\M4E"

# Analyze multiple flight directories together
DroneDatasetAnalyzer "D:\Flight_001" "D:\Flight_002" "D:\Flight_003" -o report.md

# Custom output path, more samples per flight
DroneDatasetAnalyzer "D:\Flights\Flight_001" -o report.md --samples 15

# Skip elevation API (no internet needed)
DroneDatasetAnalyzer "D:\Flights\Flight_001" --skip-elevation

Sample Output

═══ MISSION SUMMARY ═══
  Platform:       DJI Matrice 4E
  Photos:         5,394 across 1 day(s)
  Flights:        3
  Capture Groups: 1
  AGL:            63.7 m mean (53.3-82.3 m range, WGS84 ellipsoidal datum)
  Speed:          4.8 m/s median (0.2-14.7 m/s range)
  Capture Time:   1h 5m

  ── Capture at ~64 m AGL (5,394 photos, 3 flight(s)) ──
     Altitude: 64 m AGL (rel 31–64 m)  |  GSD: 1.71 cm/px  (terrain follow)
     Overlap:  77% forward, 79% side
     Speed:    4.8 m/s cruise  |  transit 9.5 m/s (17%)
     Gimbal:   Smart Oblique at 45°

The tool generates a full Markdown report with dynamic sections: Equipment, Location, Mission Overview (with capture group summary table), Elevation & Terrain (global), one section per capture group (with full Altitude/GSD, Overlap, and Gimbal detail), Flight Details (per-day tables with group labels), Camera Summary, and Methodology Notes.

How It Works

The analysis pipeline is designed for speed — it reads as few files as possible:

  1. Directory Scanning (0 file reads) — Recursively finds all JPEG files across input directories
  2. Filename Parsing (0 file reads) — Extracts timestamps and sequence numbers from DJI's DJI_YYYYMMDDHHMMSS_NNNN_V.jpg naming convention
  3. Flight Segmentation (0 file reads) — Splits at >30s gaps, merges brief pauses unless the sequence counter resets (= power cycle)
  4. Metadata Sampling (~45 file reads) — Reads EXIF + XMP from 9 evenly-spaced photos per flight
  5. Capture Group Classification (0 file reads) — Groups flights by altitude band using sampled metadata
  6. Elevation & AGL (~5 HTTP requests) — Queries SRTM ground elevation for the sampled photos, resolves the AbsoluteAltitude vertical datum (subtracting the EGM96 geoid undulation for ellipsoidal platforms), and stamps a datum-corrected AGL on each sampled photo
  7. Per-Group Analysis (~500 file reads per classified group) — Computes AGL statistics + terrain-follow detection, gimbal configuration, and reads consecutive photos for overlap computation within each altitude band — with GSD/footprint driven by the measured AGL

Altitude Semantics

DJI photos carry two altitudes, and neither is "height above ground" by default:

XMP field Meaning Pitfall
RelativeAltitude Height above the takeoff point Diverges from height above ground under terrain follow or when terrain slopes away from the takeoff point — GSD/overlap computed from it are wrong
AbsoluteAltitude Drone altitude in a vertical datum that varies by platform RTK-capable platforms (M4E, M3E, M300/350, P4RTK) write WGS84 ellipsoidal heights; consumer platforms write EGM96 MSL. Differencing an ellipsoidal height against orthometric SRTM elevations inflates AGL by the geoid undulation (~17–40 m over most land)

The analyzer resolves the datum (RtkFlag tag → ellipsoidal; consistency heuristic as fallback; --altitude-datum to force), subtracts the EGM96 geoid undulation where needed using an embedded 15-minute EGM96 grid (GeographicLib's egm96-15.pgm, derived from public-domain NGA data — no internet needed for the geoid), and uses the resulting measured AGL for GSD, footprint, and overlap.

Total: ~1,500+ file reads for a 5,000-photo multi-group dataset. Analysis completes in ~30 seconds over a network share, or a few seconds on local SSD.

Metadata Sources

Source Data Extracted
DJI Filename Capture timestamp, sequence number
EXIF IFD GPS coordinates, altitude (MSL), exposure, aperture, ISO, focal length, image dimensions
DJI XMP Relative altitude, gimbal pitch/yaw/roll, flight yaw, ground speed, calibrated focal length, RTK status, sensor temperature, device serial numbers

EXIF is parsed from raw TIFF/IFD binary format. XMP is extracted via regex on the embedded XML. No external image libraries required.

Requirements

  • .NET 10 SDK (for building from source)
  • Or any of the pre-built releases (self-contained, no SDK needed)
  • DJI drone photos with standard naming convention and EXIF/XMP metadata
  • Internet connection for elevation API (optional — use --skip-elevation to skip)

Supported Drones

Tested with:

  • DJI Matrice 4E (M4E)

Should work with any DJI drone that uses the standard DJI_YYYYMMDDHHMMSS_NNNN_V.jpg filename convention and drone-dji:* XMP namespace (Mavic, Phantom, Matrice, Mini series, etc.).

Building

# Debug build
dotnet build src/DroneDatasetAnalyzer.csproj

# Release build
dotnet build src/DroneDatasetAnalyzer.csproj -c Release

# Self-contained single-file executable
dotnet publish src/DroneDatasetAnalyzer.csproj -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -o publish/

License

Apache License 2.0 — see LICENSE.

The embedded EGM96 geoid grid (src/Resources/egm96-15.pgm) comes from the GeographicLib geoid distribution and is derived from public-domain NGA EGM96 data.

About

Built by Alos — a Norwegian drone services company specializing in imaging, mapping, inspection, and reality capture.

About

CLI tool that analyzes DJI drone photo datasets and extracts flight timelines, camera settings, overlap geometry, gimbal configuration, altitude/GSD, and terrain elevation from EXIF + XMP metadata.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages