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 ↗





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
| Measure | Top-hat baseline (no training) | Fine-tuned Faster R-CNN |
|---|---|---|
| AP@0.5 | 0.139 [0.108–0.177] | 0.885 [0.839–0.926] |
| Precision | 14.7% (4,759 / 32,371) [12.7–17.0] | 96.7% (7,154 / 7,401) [95.2–97.8] |
| Recall | 56.5% (4,759 / 8,429) [48.7–64.2] | 84.9% (7,154 / 8,429) [80.0–89.6] |
| False alarms on drone-free frames | 99.5% (1,147 / 1,153) [98.2–100.0] | 3.5% (40 / 1,153) [0.8–8.9] |
On a dataset it never saw
| Measure | Top-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 alarm | 77.5% (3,777 / 4,872) [69.1–85.0] | 23.0% (1,119 / 4,872) [16.1–30.3] |
| Birds mistaken for a drone | 0.1% (3 / 4,330) [0.0–0.2] | 3.1% (133 / 4,330) [1.4–5.3] |
| Aeroplane frames with a drone alarm | 89.1% (4,166 / 4,678) [82.4–94.8] | 45.3% (2,118 / 4,678) [35.6–54.6] |
| Aeroplanes mistaken for a drone | 4.7% (218 / 4,678) [1.8–8.4] | 11.8% (552 / 4,678) [7.2–16.6] |
| Helicopter frames with a drone alarm | 78.7% (2,689 / 3,415) [68.6–88.0] | 51.7% (1,764 / 3,415) [40.3–63.5] |
| Helicopters mistaken for a drone | 6.3% (215 / 3,415) [2.3–11.2] | 19.1% (651 / 3,415) [11.3–29.0] |
Training
| Epoch | Validation AP@0.5 | Train loss | Minutes |
|---|---|---|---|
| 1 | 0.8916 | 0.0405 | 43 |
| 2 | 0.9303 | 0.0406 | 44 |
| 3 | 0.9373 | 0.0414 | 45 |
| 4 | 0.9374 | 0.0415 | 45 |
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 et al. drone detection dataset, Zenodo (CC0 1.0) ↗