2026 · drone video · laptop CPU

Aerial Track and Range

Tracking and ranging from a single drone camera

A camera tells you which direction something is in, but not how far away it is. I built a system that takes drone video, finds and follows every person and vehicle, and works out how far away each one is. Every distance comes with an error bar, and the system says when not to trust it. It all runs on a laptop with no GPU.

2.4%

median distance error on synthetic flights with exact truth

flat ground, given the true height: 14.7%

Real flight from the AU-AIR dataset, not used in development. It was recorded at 5 frames a second; the frames in between are generated so it plays smoothly. Green tags are reliable, amber uncertain.

A camera gives direction, not distance

assumed flat groundlocal surface, triangulateda moment latercar 0.8450% too faron the carwhere?camera
A diagram of the idea, drawn to explain it. The 50% belongs to this drawing, not to a measurement.

Step 1 · The ray

Each box tells me the direction of an object from the camera. To turn that into a distance, I draw a line from the camera through the bottom of the box, where the object touches the ground, and find where that line meets the ground.

Step 2 · The usual shortcut

The catch is knowing where the ground is. The usual shortcut assumes the ground is flat and that the drone knows its height above it. On a slope the line carries on to an imaginary flat ground, and the distance comes out far too long. A real drone does not know its height above the ground anyway.

Step 3 · Terrain from motion

So I estimate the shape of the ground from the drone's own motion. The same patch of ground, seen from two positions a fraction of a second apart, can be triangulated, the way two eyes judge depth. The line now meets the real surface, at the car.

Follow one car through the system

Every frame passes through seven steps. Each one adds something to what the system knows about the car, shown in the box under each step. The ranging step also takes two extra inputs: where the drone is, and the shape of the ground beneath it.

  1. 1

    Video frame

    from a single drone camera

    Adds: 1920 × 1080 pixels

  2. 2

    Detect

    YOLO26n, fine-tuned on drone footage

    Adds: box: car 0.84

  3. 3

    Track

    BoT-SORT with camera-motion compensation

    Adds: car, ID 12

  4. 4

    Range

    a ray from the camera to the ground

    Adds: ID 12: 46 m

    • drone pose and height
    • terrain from motion
  5. 5

    Uncertainty

    propagated, calibrated, flagged

    Adds: 46 ± 3 m, reliable

  6. 6

    Kalman filter

    position, speed and heading

    Adds: 8 m/s, heading 270°

  7. 7

    Output

    a table and an annotated video

    Adds: one row in tracks.csv

Example values, to show what each step adds.

Detect and track

I fine-tuned a small YOLO26n detector on VisDrone, a dataset of drone footage, and paired it with the BoT-SORT tracker, which corrects for the camera's own movement. Each colour and number in the video is one identity, kept from frame to frame.

I left out appearance-based re-identification on purpose: the tracker uses only motion and overlap, so it never analyses faces.

VisDrone test footage, tracked by my system.

Fine-tuning did most of the work

Off the shelf, the detector misses almost everything seen from above. Drag the line across the video to compare it with the fine-tuned version on the same footage.

off the shelf

0.32

fine-tuned

0.62

Mean identity F1 (IDF1) on validation data: how long each object keeps the same identity. Higher is better. On the test set, vehicles reach 0.760 and people 0.436.

off the shelffine-tuned
VisDrone validation footage. Left of the line: the detector off the shelf. Right: after fine-tuning.

Small people are the weak point

How big something is in the picture is measured in pixels, the dots that make up the image. All four people marked here are from this one frame. The closest is 159 pixels tall; the furthest only 24, a smudge of colour.

The detector finds 91% of people taller than 128 pixels, but only 16% of those between 16 and 32 pixels, and nearly a third of the people in the test footage are that small.

A busy shopping street seen from a low drone, with four people marked at different distances: 159, 107, 47 and 24 pixels tall.
VisDrone test frame. People marked from the dataset's own annotations.
People foundVehicles found
Share of objects found on the VisDrone test set, by height in pixels. Under each pair of bars, a real person of that size from the street above, enlarged to the same height so you can see how little detail the detector gets.

Measured against exact truth

To score distances I need to know the right answer. Mid-Air is a simulated dataset of low drone flights where the true distance of every pixel is known. I froze every setting, then ran the 9 test flights once.

On the same samples, terrain from motion had a median error of 2.4%. Flat ground managed 14.7%, even when I gave it the true height, which a real drone would not have. Terrain from motion was closer on 78% of samples and had the lower median on 8 of 9 flights.

It is not always better. On flight 5 it was worse (17.1% against 10.3%), and one estimate in ten is still more than 35% off.

0%20%40%60%Terrain from motionmedian 2.4%1 in 10 above 35%Flat ground, true heightmedian 14.7%1 in 10 above 64%
Mid-Air test flights, the 78% of samples where both methods give an answer. The dot is the median; the line runs to the 90th percentile.

The flat-ground shortcut breaks on hills

The steeper the ground, the worse the flat assumption gets: its error grows from 6% on level ground to 24% on slopes above 45°. Terrain from motion stays at or below 3.7% on slopes up to 45°.

Terrain from motionFlat ground, true height
0%10%20%30%0°15°30°45°60°slopeto 56%
Median range error by ground slope on the Mid-Air test flights. Thin vertical lines are confidence intervals.

Error bars that say how far to trust it

Every distance comes with an error bar: a range the true distance should fall inside. "46 ± 3 m" means somewhere between 43 and 49 metres. An error bar is only honest if the truth really does land inside it as often as it claims.

I work out each error bar from the sensor noise, then calibrate them on separate flights using split conformal prediction, so they are wide where the system is unsure and narrow where it is not.

What an honest error bar looks like

30 m40 m50 m60 mtrue distance46 ± 3 mtruth inside: honest46 ± 1 mtruth outside: overconfident
An illustration of the idea, not measured data.

Promised 90 in 100. Delivered 84.

A 90% error bar promises to contain the truth 90 times in 100. Straight from the sensor noise, mine managed 74. After calibration, 84. That is still 6 short, which tells me the test flights differ more from the calibration flights than the method assumes, so I report it as it is.

A small model, built on features I can explain, also raises a warning flag. It catches 56% of the estimates that are more than 10% off.

Promised90 in 100

Before calibration74 in 100

16 short

After calibration84 in 100

6 short
Out of every 100 distance estimates, how many had the truth inside their 90% error bar. Mid-Air test flights.
simulation

Each dot is a distance

This is not real footage. It is Mid-Air, a simulated drone flight made in a game engine: a camera flying low over grass, rocks and hills. Because the world is simulated, the true distance to every pixel is known, so every estimate my system makes can be checked exactly.

Each mark is one distance estimate, pinned to its spot on the ground as the drone flies past.

  • Within 10% of the true distance
  • More than 10% off
  • Amber: the warning flag was raised

How far the number transfers

The 2.4% uses the simulator's exact camera positions. A real drone's navigation is not exact, so I added noise to every pose and re-ran the development flights.

Errors shared by every frame barely matter: a 5 m GPS offset leaves terrain from motion at 2.7%, while flat ground jumps to 67%. Errors that change from frame to frame matter a lot, because triangulation depends on the small change in position between frames. Past about 7 cm of per-frame noise, flat ground wins.

In practice the method needs the short-term accuracy of an inertial or visual-inertial navigation system, not raw GPS.

Terrain from motionFlat ground, true height
0%20%40%60%2 cm10 cm1 mlines cross near 7 cm
Median range error against random per-frame position noise, Mid-Air development flights.

Three navigation grades

Combining both kinds of error at three assumed levels of navigation quality. These are my assumptions, not product specifications. Ranging the bottom of a detected car's box, rather than a point on the ground, adds its own 3% short bias, so even with exact poses a car is 5.6% off at the median.

Median range error for three assumed navigation grades
NavigationTerrain from motionFlat ground
Good6.6%22%
Typical11.7%40%
Poor40%78%

Median range error. Flat ground is given the true height in every row.

On real footage

AU-AIR records real flights with GPS and altitude, but no camera calibration and no camera tilt. So I estimated both: the focal length from GPS motion against image motion on separate flights (1259 pixels), and the tilt, frame by frame, from how the ground moves in the footage.

There are no true distances in AU-AIR, so accuracy can't be measured here. What can be measured is whether the system gives the same answer twice.

Looking straight down on a held-out AU-AIR flight. The faint ring marks 10 m on the ground.

What held up on real footage, and what didn't

Held up

7.6%

Consistent distances. Parked cars should stay put, and the system agrees: their estimated positions repeat within 7.6% of their distance, across 343 vehicle segments.

Did not transfer

0.21

Detection score on vehicles (AP50; 0.02 on people). The detector learned on VisDrone and transfers poorly to this footage, so many vehicles are never ranged.

11%

Implausible speeds. Vehicle tracks that imply more than 70 km/h at a junction, most likely from shallow viewing angles and identity switches.

No GPU. A laptop CPU, the AMD Ryzen 7 5700U.

Fast enough on a laptop

Same clip, played at the speed the system can process it. On the left, full accuracy. On the right, the version I tuned for video rate.

9.6 fps full accuracy

3.5× faster

33.4 fps video rate

The right side shows every frame of this 25 fps clip, since 33.4 fps is faster than the clip itself.

How I got from 9.6 to 33.4

At full accuracy, with the detector exported to ONNX, the pipeline runs at 9.6 frames per second. To reach video rate I used a smaller input, ran the detector only on every second frame (the tracker predicts in between), and ran detection alongside tracking.

The cost: identity F1 falls from 0.617 to 0.536. Each result still arrives 47 ms after its frame, so 30 fps holds for throughput, not for the delay on a single frame.

Every setting I measured

0.500.550.600 ms50 ms100 ms150 msIDF130 fps10 fps9.6 fps, full accuracy33.4 fps, video rate
Tracking accuracy (IDF1, validation) against time per frame. The best trade-offs are joined. Three INT8 settings took 360 to 719 ms and are off the chart.

The one test still missing

Each dataset checks a different part of the system, and none has everything. So no single test yet runs the whole chain, from video to distance, against known object distances.

The next step I would take is one setup with all three: a drone flown past a car carrying a GPS logger, or a simulator with vehicles and people, scored end to end.

Every known limitation, with numbers
What each dataset provides
DatasetReal footageLabelled objectsTrue distances
VisDronescores trackingyesyesno
Mid-Airscores rangingnonoyes
AU-AIRreal flightsyesyesno
Next testa drone, a car, a GPS loggeryesyesyes

How it is built

  • Python
  • PyTorch
  • Ultralytics YOLO26
  • BoT-SORT
  • ONNX Runtime
  • Kalman filter
  • Conformal prediction
  • pytest
  • 382 tests, run by CI on every push, on synthetic data
  • Every number on this page generated from a results file
  • Each test split run once, after every setting was frozen
  • Every design choice logged with its reason and evidence
The code, results and documentsaerial-track-and-rangegithub.com/LukeA77/aerial-track-and-rangeView on GitHub

Footage and data: VisDrone2019 (Zhu et al., IEEE TPAMI 2021), Mid-Air (Fonder and Van Droogenbroeck, CVPR Workshops 2019, CC BY-NC-SA 4.0) and AU-AIR (Bozcan and Kayacan, ICRA 2020, CC BY 4.0). Detector and tracker from Ultralytics (AGPL-3.0). People and vehicles are tracked as boxes only, with no face analysis.

Have a role in mind?

If you are looking for a spark of curiosity, energy and growth in your team, and have a role that suits my CV, let me know. Email is the fastest way to reach me.

Contact · emaillukea808@gmail.com

Guildford, UK · Right to work in the UK, no sponsorship needed