All projects

AI, computer vision, thermal infrared

Thermal Drone Detection

  • Full 4-epoch run
  • public data only

A detector for small drones in thermal (infrared) video, trained and tested only on public datasets. A COCO-pretrained Faster R-CNN is fine-tuned on Anti-UAV300 and compared with a training-free hot-spot detector under the same protocol. A second public dataset, never used for training or tuning, shows how well it generalises and how often birds, aeroplanes and helicopters set it off. There is no live demo.

Code on GitHub: hyh4867/thermal-drone-detection ↗

Thermal frame of tower blocks with a green label box around a 15-pixel drone near a rooftop, and an enlarged view; the model drew no box.
Missed small drone (15.5 px) against buildings · green = label, no box above threshold · first (1-epoch) model · Anti-UAV300 test, sequence 20190925_200805_1_2, frame 348 · data: Jiang et al. 2021, Anti-UAV (MIT License).
Thermal frame with a tree line and a green label box around a faint drone just above the trees, enlarged on the right; the model drew no box.
Missed distant drone (10.4 px, Distant bin) above a tree line · green = label · first (1-epoch) model · Svanström et al. 2021, IR_DRONE_061, first frame (CC0 1.0).
Thermal frame of sky above bare trees with a red box scored 0.98 around a small warm object, enlarged on the right.
Bird boxed as a drone (score 0.98, first-run threshold 0.90) · first (1-epoch) model · the bird is unlabelled in this first frame · Svanström et al. 2021, IR_BIRD_033 (CC0 1.0).
Dark thermal frame with a red box scored 0.99 around a bright drone-shaped object, enlarged on the right.
Alarm on a frame labelled drone-free (score 0.99) · first (1-epoch) model · the object looks drone-shaped, so this may be a labelling gap rather than a model error; not checked · Anti-UAV300 test, sequence 20190925_193610_1_4, frame 900 · data: Jiang et al. 2021, Anti-UAV (MIT License).
Thermal frame IR_BIRD_033 with a 0.98 model alarm and an enlarged inset; the frame has no bird label, so the target is unverified.
High-score alarm on an unlabelled first frame (stored score 0.98, first-run threshold 0.90) · first (1-epoch) model · not a verified drone · Svanström et al. 2021, IR_BIRD_033 (CC0 1.0). This frame was the project's home-page thumbnail until round 3; the thumbnail now shows a verified true positive.

The question

Drones in thermal video are often only a few dozen pixels across, and birds or aircraft can look much the same. How far does a pretrained detector get after fine-tuning on public thermal video, compared with a simple hot-spot detector, and what happens on footage from a different camera and site?

What I built

A data pipeline for Anti-UAV300 (infrared videos only) and for the Svanström et al. 2021 multi-sensor drone dataset. It checks each video's frame count against its labels, extracts frames, and keeps the second dataset for evaluation only. Five videos whose labels did not line up with their frames were excluded before any model was run.

While splitting the data I found that the official Anti-UAV train and validation sets share 26 of their 27 source videos (a sequence's name gives its source video). Splitting by clip would let nearly identical scenes appear on both sides, so I merged the two sets and re-split them by source video: 22 source videos for training and 5 for validation. The official test set (91 sequences from 10 other source videos) was kept as it was.

The training-free baseline marks hot or cold spots with a morphological top-hat filter and boxes them. Its kernel size, threshold and a mask for the text the camera burns into each frame were chosen on validation data only.

The model is torchvision's Faster R-CNN with a ResNet-50 feature pyramid (BSD-3-Clause), fine-tuned for four epochs on an Apple M2 with smaller anchors (from 8 px), 320-pixel crops and random down-scaling. I chose it over Ultralytics YOLO because YOLO is AGPL-3.0, which would place copyleft obligations on this MIT-licensed project.

Results on the Anti-UAV300 test set

Both methods were scored on the same 9,582 frames from the 91 test sequences (8,429 drone boxes; 1,153 frames without a drone). The score threshold was chosen once on the 1,596 validation frames (highest F1: 0.954 for the model, 4.94 for the baseline) and applied unchanged everywhere. Brackets: 95% intervals from a video-level bootstrap (1,000 resamples of the test sequences).
MeasureTop-hat baseline (no training)Fine-tuned Faster R-CNN
AP@0.50.139 [0.108–0.177]0.885 [0.839–0.926]
Precision14.7% (4,759 / 32,371) [12.7–17.0]96.7% (7,154 / 7,401) [95.2–97.8]
Recall56.5% (4,759 / 8,429) [48.7–64.2]84.9% (7,154 / 8,429) [80.0–89.6]
False alarms on drone-free frames99.5% (1,147 / 1,153) [98.2–100.0]3.5% (40 / 1,153) [0.8–8.9]

On a dataset it never saw

Svanström et al. 2021, every fifth frame; never used for training or tuning. Distance bins follow the dataset's own labels. A frame alarm is any drone box above the threshold on a frame of a bird, aeroplane or helicopter video; an object mistaken for a drone is a drone box overlapping that labelled object with IoU ≥ 0.5, counted over frames where the object is labelled. Brackets: 95% intervals from a bootstrap over videos.
MeasureTop-hat baseline (no training)Fine-tuned Faster R-CNN
Drone recall, all distances (154 videos)9.6% (899 / 9,382) [6.4–12.5]48.6% (4,561 / 9,382) [42.1–54.8]
Close, under 20 m (23 videos)25.1% (367 / 1,462) [15.0–35.8]66.0% (965 / 1,462) [54.0–77.2]
Medium, 20–60 m (93 videos)9.6% (529 / 5,528) [6.0–13.0]57.4% (3,175 / 5,528) [50.1–64.4]
Distant, over 60 m (38 videos)0.1% (3 / 2,392) [0.0–0.4]17.6% (421 / 2,392) [9.8–26.7]
Bird frames with a drone alarm77.5% (3,777 / 4,872) [69.1–85.0]23.0% (1,119 / 4,872) [16.1–30.3]
Birds mistaken for a drone0.1% (3 / 4,330) [0.0–0.2]3.1% (133 / 4,330) [1.4–5.3]
Aeroplane frames with a drone alarm89.1% (4,166 / 4,678) [82.4–94.8]45.3% (2,118 / 4,678) [35.6–54.6]
Aeroplanes mistaken for a drone4.7% (218 / 4,678) [1.8–8.4]11.8% (552 / 4,678) [7.2–16.6]
Helicopter frames with a drone alarm78.7% (2,689 / 3,415) [68.6–88.0]51.7% (1,764 / 3,415) [40.3–63.5]
Helicopters mistaken for a drone6.3% (215 / 3,415) [2.3–11.2]19.1% (651 / 3,415) [11.3–29.0]

Training

Validation AP@0.5 on all 1,596 validation frames after each epoch. Epoch 4 scored highest and was kept; the last two epochs differ by 0.0001. Epochs 2–4 were resumed from the epoch-1 checkpoint with a low-memory setting (see Limits).
EpochValidation AP@0.5Train lossMinutes
10.89160.040543
20.93030.040644
30.93730.041445
40.93740.041545

Evaluation

A box counts as found if it overlaps a labelled drone with IoU ≥ 0.5. AP@0.5 is the area under the precision–recall curve. The false-alarm rate is the share of drone-free frames that get at least one box above the threshold.

Anti-UAV test: 9,582 frames from the 91 test sequences, 8,429 drone boxes and 1,153 drone-free frames. Recall by target size adds 340 frames with small targets, because such targets are rare in this dataset.

Svanström: every fifth frame, never used for training or tuning. For the bird, aeroplane and helicopter videos I report two measures: how often a frame raised any drone alarm, and, on frames where the object is labelled, how often the drone box sat on that object.

Brackets are 95% intervals from a video-level bootstrap with 1,000 resamples. The resampling unit is the test sequence on Anti-UAV and the video on Svanström.

Key findings

On the Anti-UAV test set, fine-tuning raised AP@0.5 from 0.139 to 0.885 and cut false alarms on drone-free frames from 99.5% to 3.5%. The training-free baseline raised an alarm on all but 6 of the 1,153 drone-free frames.

Recall by target size (√(w·h)) was 71.8% for 8–16 px (262 / 365), 78.2% for 16–32 px (1,537 / 1,965), 86.7% for 32–64 px (5,440 / 6,272) and 100% above 64 px (150 / 150). It found none of the 17 targets under 8 px.

On the dataset it never saw, drone recall fell from 84.9% to 48.6%, and to 17.6% for drones more than 60 m away. A score measured within one dataset did not carry over to another camera and site.

Most alarms in bird, aeroplane and helicopter videos were not on the labelled object. 23–52% of their frames raised a drone alarm, but the drone box sat on the bird or aircraft itself in only 3–19% of labelled frames. Some of the rest may be unlabelled objects or boxes short of IoU 0.5; I did not check them one by one.

My role and the agent workflow

I set the rules: public datasets only, video-level splits, thresholds chosen on validation data only, and every number taken from a run. For the first write-up I stopped after one epoch and scored reduced samples; the full four-epoch run with full evaluation has since replaced every number on this page.

Claude implemented the data pipeline, baseline, training and evaluation in bounded steps on my instructions. I reviewed its output and keep responsibility for the claims on this page.

Limits

Only 17 test targets were under 8 px, and neither method found any of them (0 / 17), so there is no conclusion about very small drones. Some missed small-target labels sit at the edge of the frame with no drone visible, so part of these misses may be labelling errors; I did not check them one by one.

The baseline's chosen setting has k = 1.5, the lower edge of its search grid, so the baseline may be slightly understated.

The Anti-UAV test set comes from only 10 source videos. Its 91 sequences, the bootstrap units, are drawn from those 10, so the intervals are wide, and because sequences from the same source video are correlated the real uncertainty may be wider still.

Training did not run in one go. Epoch 1 used the original setting (2 data-loader workers, batch 8); epochs 2–4 resumed from the epoch-1 checkpoint and optimizer state with a low-memory setting (no workers, 2 images × 4 gradient-accumulation steps, effective batch 8). PyTorch's global random state was not restored, so the detector's random region sampling differs from an uninterrupted run, and retraining on MPS can change the last decimals.

Both datasets come from specific cameras and sites, and the second one was recorded in daylight only. These results say nothing about other sensors, weather or operational use.

The failure examples below were made with the first (1-epoch) model and have not been regenerated with the full-run model.

Evidence and reproducibility

Code, configuration and the full-run results (results/full/: the comparison table and the metric files for both methods) are in the public repository, along with the first run's results and the failure gallery. Every result file records a hash of the configuration, the SHA-256 of each dataset archive and the commit of my private working repository at run time; the public repository starts from a fresh history. The seed is fixed at 0.

Datasets: Anti-UAV300 (repository under the MIT License) and the Svanström et al. multi-sensor drone dataset (data released under CC0 1.0; article under CC BY 4.0). Model weights and raw videos are not published.

Jiang et al., Anti-UAV: A Large Multi-Modal Benchmark for UAV Tracking (arXiv:2101.08466) ↗

Anti-UAV dataset repository (MIT License) ↗

Svanström, Alonso-Fernandez & Englund, A dataset for multi-sensor drone detection, Data in Brief 39, 107521 (2021) ↗

Svanström et al. drone detection dataset, Zenodo (CC0 1.0) ↗

Back to all projects