fabians.site
← all writing
article Jul 2 · 4 min

Protecting endangered sea turtles with machine learning

Automatically cataloging drone footage to help improve sea turtle poaching alert systems.

For my master's thesis I worked with DELT, an NGO that builds computer vision models to spot sea turtles in drone footage. Conservation groups around the world use those models to find nesting sites, so they can check the beach for poachers and protect the eggs before anyone reaches them.

I wanted a project with a tangible, positive effect on the world that still let me work with ML, and DELT gave me exactly that: they shared their full catalog of footage and pointed me at a hard problem they were facing.

That problem: a detector only knows the footage it was trained on, and turtle footage looks nothing alike from one place to the next. The same species over a bright reef, a deep green swell, or murky coastal water barely reads as the same thing to a model, and what it learned in one water will probably fail in the next.

Two sea turtles over turquoise reef shallows, from a drone. Japan
A sea turtle at the surface of deep green water, from a drone. Costa Rica
A sea turtle in murky green coastal water, from a drone. Florida
Same species, three countries, three very different waters.

The problem

Most sea turtle species are endangered, and one of the most direct threats is egg poaching. On unprotected beaches in Costa Rica, poachers take more than half of some species' nests.

DELT fights this with computer vision: conservation groups fly drones over nesting beaches, and DELT's models spot the turtles and flag which nests to protect before poachers reach them.

This is domain shift, and it is a headache: one model, footage from everywhere, worse in each new place. Specializing a detector per condition would help, but first you need to know which conditions exist, and nobody can sort a huge catalog by hand.

Can we sort the footage into its capture conditions automatically, so each detector is tuned to the world it works in?

One detector Clear water Murky water Night vision Holds up Struggles Struggles
One detector, three conditions. Tap a condition to see how it holds up.
The same model handles every condition, and its accuracy does not hold up equally. Illustrative.

How I approached it

The tool for this is clustering: letting a computer sort things into groups by similarity, without anyone telling it the groups ahead of time.

Instead of labels, I describe each clip with 21 numbers, the features of the footage: how bright and sharp the image is, the color of the water, how big the turtle is in the frame and where it sits, how many turtles show up per frame, and the drone's altitude, which I had to estimate myself (more on that later). Clips with similar features land together, and each group is a capture regime: a recurring kind of footage.

Group 1Group 2Group 3
Clustering
Drone clip, group 1 regimeDrone clip, group 2 regimeDrone clip, group 3 regimeDrone clip, group 1 regimeDrone clip, group 2 regimeDrone clip, group 3 regimeDrone clip, group 1 regimeDrone clip, group 2 regimeDrone clip, group 3 regime
Real clips ride in, get sorted by the clustering step, and come out grouped by regime.

To be sure the groups were real and not one algorithm's quirk, I ran three different clustering methods, each with its own idea of what a group even is: K-means, Ward, and HDBSCAN.

Each tile is one drone clip. The three methods sort the same clips like this:

center
K-means You choose how many groups. Each clip joins whichever one it sits closest to.
cut into 3
Ward Every clip starts on its own, then the two most alike keep pairing up, until you split them into groups.
noise
HDBSCAN Wherever clips bunch up close together, that is a group. The loners out on their own get left out.

All three land on nearly the same grouping, 0.91 on a scale where 1 is identical and 0 is random (it's the Adjusted Rand Index, if you want to look it up). HDBSCAN is the real tell: I never told it how many groups to look for, and it still found the same structure on its own, plus 15 clips it refused to place.

You can see the agreement instead of taking my word for it. Take each clip's handful of numbers and squash them down to a flat map (the trick is called PCA): every clip becomes a dot, and clips that look alike sit close together. Color each dot by its group, switch the algorithm, and watch how little changes:

K-means, told to find 3 groups: close-up 5, high-altitude 28, coastal 506.

One dot per clip, similar clips close together. The 2D squash keeps 38.8% of the information: a view, not a proof.

Three methods with very different assumptions settling on the same groups means the structure is a property of the footage, not of any single algorithm.

The hard parts

Two things fought me from day one.

One campaign was almost the entire catalog

The most annoying part of the whole project: everything was full of Nishizawa, the big survey campaign from Japan. The catalog is seven campaigns, two from Japan, one each from Costa Rica, Florida and the Bahamas, a batch scraped from public YouTube videos, and a small set from Conservation AI. It is very hard to work with a dataset where most of the data is the same thing.

87%

of all 539 clips are one campaign, Japan (471 of them). The other six, the teal corner, share the last 13%.

That is dangerous: clustering can "find" groups that are really just the dominant campaign in disguise. So I checked it the other way around, dropping each campaign in turn and re-clustering.

Drop Japan: 471 clips gone, 87% of everything, and the survivors keep nearly the same groups. 0.84 out of 1.

The same map as before; dropped clips disappear and the survivors regroup. Color is the new group.

Dropping the giant barely moves the grouping: 0.84 on that same 1-is-identical scale. The scare comes from the small campaigns: drop one of them and the score collapses to 0.09.

But that 0.09 is the imbalance talking, not the groups dissolving. The small campaigns anchor the shape of the big cluster, so without them the algorithm re-slices the big cloud, and a score measured over all 539 clips falls hard. The group I actually trust, the high-altitude one, comes back almost unchanged.

Most clips never recorded their altitude

The single most useful number, how high the drone was flying, was almost never in the metadata. So I estimated it. A sea turtle's shell is a roughly known size, about 0.65 m across, so how wide it looks in the frame tells you how far the camera was: fill the frame and the drone was low; a tiny speck and it was high.

It is standard pinhole geometry. Feed it the turtle's width plus the camera's focal length and sensor size (here, 4.49 mm focal, 6.17 mm sensor), and out comes the altitude.

what the camera sees, looking straight down

The turtle spans 12% of the frame's width, so the drone was about 3.9 m up.

altitude = real size × focal length ÷ (share of the frame × sensor size)

So, did it work?

The sorting part, yes. The clips fall into three capture regimes: subaquatic close-ups, high-altitude passes, and coastal mid-altitude flights.

Subaquatic close-up
Underwater drone still, turtle large in frame (example 1 of 4).Underwater drone still, turtle large in frame (example 2 of 4).Underwater drone still, turtle large in frame (example 3 of 4).Underwater drone still, turtle large in frame (example 4 of 4).
High-altitude pass
High-altitude drone still, turtle tiny in frame (example 1 of 4).High-altitude drone still, turtle tiny in frame (example 2 of 4).High-altitude drone still, turtle tiny in frame (example 3 of 4).High-altitude drone still, turtle tiny in frame (example 4 of 4).
Coastal mid-altitude
Mid-altitude coastal drone still over blue water (example 1 of 4).Mid-altitude coastal drone still over blue water (example 2 of 4).Mid-altitude coastal drone still over blue water (example 3 of 4).Mid-altitude coastal drone still over blue water (example 4 of 4).
Filter by group.
The three regimes, four real clips each. Filter to one and the rest dims.

The group I trust most is the high-altitude one: 28 clips from five different projects across four regions that ended up together because the footage looks alike, not because it comes from the same place.

I did not get to train the specialist models on top of it, most of the groups are still too small to prove anything with. It would have been a nice ending, but chasing it with this data would have produced a number nobody should trust.

What I could do is make the sorting repeatable: turtle-cluster, a package DELT re-runs on the whole catalog in about three minutes, so the groups keep growing as new footage comes in.

The specialist models are the part I hope someone builds next, on top of this.

The code is on GitHub. If you work on aerial wildlife detection and any of this is useful, tell me.