Documentation menu

DJI drone

For aerial deliveries from DJI drones. Unusually among these templates, there is no pose file to prepare: position, orientation and camera calibration are all read out of the XMP and EXIF metadata DJI already embeds in each JPG.

Folder layout#

<dataset bucket>/
├── aerial/
│   ├── jpg/
│   │   ├── flight-01/            one subfolder per flight = one set
│   │   │   ├── DJI_20260612093000_0001_V.JPG      wide camera
│   │   │   ├── DJI_20260612093000_0001_T.JPG      thermal, if fitted
│   │   │   └── DJI_20260612093002_0002_V.JPG
│   │   └── flight-02/
│   │       └── DJI_20260612101500_0001_V.JPG
│   └── meta/                     optional
│       └── flight-01/
│           └── DJI_20260612093000_Timestamp.MRK
└── pointcloud/                   optional
    └── scan.las

The folder names aerial/jpg and aerial/meta are fixed — there are no alternative spellings for this template.

Each subfolder under aerial/jpg/ becomes one set, named after the folder. Photos placed directly in aerial/jpg/ (no flight folder) land in a set named 1. Listing is recursive, so deeper nesting works, but only the first path segment names the set.

At least one photo is required; otherwise the run fails.

Photos#

Extensions.jpg and .jpeg, case-insensitive
Metadata sourceThe drone-dji XMP namespace, tiff:Model, xmp:CreateDate, EXIF pixel dimensions and optics, and DewarpData when the camera ships one
Read sizeValidation: first 64 KiB, then 256 KiB / 1 MiB if the XMP packet is truncated. Indexer: first 256 KiB, retry 1 MiB

Deliver the photos as the drone wrote them. Re-encoding, stripping EXIF, or running them through an editor that drops XMP will remove exactly the data this template depends on.

Capture time#

Each JPG's XMP carries the capture instant (UTCAtExposure or xmp:CreateDate). That instant is UTC, not Dutch local time. Validation reads a 64 KiB JPEG head first (retrying 256 KiB then 1 MiB if the XMP packet is truncated) and records the observed acquisition span from those timestamps, so the supplier does not have to type the dates at submit. Up to 10 % of photos may fail to parse before validation fails — the same tolerance the indexer uses.

What is read per photo: drone model and which of its cameras took the frame, latitude, longitude, ellipsoidal height, relative altitude, gimbal yaw/pitch/roll, RTK fix flag, image dimensions, focal length in pixels, principal point offset and capture time. Capture time in XMP is UTC (UTCAtExposure or xmp:CreateDate). Deliver the JPGs as the drone wrote them.

Some drones — the Matrice 4 series among them — ship no factory camera calibration at all. Those are indexed with the camera's nominal focal length and a centred principal point, which is accurate enough for footprints, viewing and search but not for photogrammetry.

Up to 10 % of photos may fail to parse before the indexer run fails. A non-fixed RTK solution is a warning, not an error — the photo is still indexed.

Thermal photos#

Dual-payload drones — the Matrice 4T and its relatives — write two JPGs per exposure: a _V from the wide camera and a _T from the thermal core. Both belong in aerial/jpg/; deliver them exactly as the drone wrote them, in the same folder.

Each becomes its own photo record, tagged rgb or tir in its bands property. They are not merged into one record, because the two cameras have different lenses: their images cover different ground and have different resolutions, so they are not two channels of one picture. A 614-shot flight therefore produces 1228 records, not 614.

Every photo gets a tilepack (.tpc). For ordinary frames that is a tiled image pyramid; for thermal frames it carries absolute temperatures in °C, decoded once here at ingest with DJI's own calibration — so a viewer reads real temperatures without needing DJI software, and the values agree with DJI's Thermal Analysis Tool.

How temperatures are calculated#

Turning raw sensor counts into a temperature depends on the distance to the target, the emissivity of its surface, and the state of the air in between. Every DJI thermal frame carries the camera's own values for these, and those are what we use — the same ones DJI's own tools read, so our temperatures match what you see there.

We deliberately offer no way to override them from our side. The person who flew the job set them in the field, against the actual subject; we would be guessing from a photograph. On the M4T survey those values are a 90 m standoff for a flight at 100 m above ground and an ambient temperature that tracks the air over the flight — measurements, not defaults.

If they are wrong, they are wrong in the camera. Fix the camera settings and re-fly, or re-deliver: nothing downstream of the shutter can recover the right answer.

Two things worth knowing: distance saturates above roughly 200 m, so a higher figure would change nothing anyway; and a _T frame from a camera whose super-resolution is on stores 1280 × 1024 pixels but measures 640 × 512 — the temperatures come from the 640 × 512 core, which is the real measurement. The photo's width/height in the API are the stored JPEG's (1280 × 1024); its thermal tilepack's root level is the measured array (640 × 512). Size the pyramid from the tilepack, not from the feature's dimensions.

The MRK file#

Optional. If present, aerial/meta/<flight>/*.MRK supplies the antenna-to-camera lever arm, which is applied per exposure and is worth roughly 10 cm of accuracy.

  • Matched on any key ending .mrk, case-insensitively. Both DJI spellings work: *_Timestamp.MRK and the bare DJI_<timestamp>_<n>_D.MRK that the Matrice 4 series writes.
  • One per flight set; if several are present in one folder, the first wins.
  • The aerial/meta/ subfolder does not have to be named after the aerial/jpg/ one when the delivery has one flight: one JPG folder and one MRK are matched to each other whatever they are called. With several flights the folder names must match, because exposure numbers restart at _0001 per flight and one MRK would fit every flight while belonging to one; sets whose names don't line up skip the correction, and the run's log says so.
  • Fields are identified by their label suffix (,N, ,E, ,V, ,Lat, ,Lon, ,Ellh, ,Q) rather than by column position, so minor format variations are tolerated.
  • Column 1 is the photo sequence number, matched against the NNNN in DJI_<timestamp>_0001_V.JPG.

A missing MRK just skips the correction. Unparseable lines are counted and warned about.

Coordinate reference system#

This template does reproject.

Photo positions come from the drone's RTK network frame, which for Dutch NTRIP networks is ETRS89, not WGS84. They are transformed from the source CRS to the dataset's CRS using PROJ with network grids.

ParameterDefault
source_crsEPSG:4937 (ETRS89 geographic 3D)

Set source_crs if your RTK corrections came from a network in a different frame. A bare number is accepted and normalised (4937 becomes EPSG:4937).

Ingest parameters#

KeyRequiredTypeMeaning
ground_heightnonumberGround elevation (tenant vertical datum, metres) for footprint projection. When absent, each photo derives its own: capture height minus the XMP RelativeAltitude.
source_crsnostringCRS of the photo positions, as EPSG:nnnn (a bare SRID is accepted). Default: EPSG:4937.

When ground_height is not set, the ground elevation is derived per photo as ellipsoidal height minus relative altitude — that is, the take-off elevation. Set it explicitly when the terrain differs materially from the take-off point.

Footprints#

Footprints are the actual image frame projected onto the ground plane, not a fixed-size square around the capture point as the legacy templates produced. Gimbal yaw is corrected for local meridian convergence, the four corner rays are intersected with the ground plane, and near-horizon rays are range-clamped.

That means an oblique frame produces a genuinely oblique footprint, and photo search by area behaves the way you would expect.

What you get back#

  • Indexed aerial photo records with position, orientation, camera intrinsics and a ground footprint, grouped per flight, each tagged with the spectral bands it carries.
  • A tilepack (.tpc) per photo for the viewer — a tiled image pyramid for ordinary frames, and absolute temperatures in °C for thermal ones. Tenants still on Omnibase also get an SZI per photo.
  • Indexed point clouds plus a merged COPC, if point clouds were delivered.

Common failures#

SymptomCause
"no photos found under aerial/jpg/"Wrong folder name — aerial/jpg is fixed for this template
More than 10 % of photos unparseablePhotos were re-encoded or edited, dropping the DJI XMP packet
Everything in one set called 1Photos were placed directly in aerial/jpg/ rather than in per-flight subfolders
Positions offset by ~10 cmNo MRK file, so the lever-arm correction was skipped
Positions off by metressource_crs doesn't match the frame your RTK network actually used
Twice as many photos as shotsExpected on a dual-payload drone: _V and _T are separate records, tagged rgb and tir
Temperatures look wrong across the whole flightThe camera was set up with the wrong standoff or emissivity — that is fixed in the camera, not here