Camera Trap Pipeline
Our trail cameras on Heart 7 took about 13,000 photos. A lot of them are empty, and one deer walking past shows up as a burst of several frames. I built a pipeline that sets the empty photos aside, isolates each animal in its own box and identifies the species from that crop.
Photos from the same visit are grouped, so one deer counts once, not once per photo. It also flags camera problems, like a clock that reset when the batteries died or a camera that went dark for days, and it saves its progress after every step so a crashed run picks up where it stopped.

View the code (opens in a new tab)Read the README (opens in a new tab)Open the live report (opens in a new tab)
The problem
Turn folders of trail-camera photos, with empty frames, bursts, reset clocks and dead cameras, into counts that can be trusted.
What I built
A resumable pipeline: photo quality checks and near-duplicate grouping, MegaDetector to box each animal, SpeciesNet to identify the species in each box, and grouping of each camera's bursts into visits.
What it produces
Tables of photos, detections, species and visits, per-camera health checks, charts and an HTML report.
The public version runs on drawn, synthetic photos with the same field problems planted in them.
The demo photos are drawn by code, with planted field problems. Real public camera-trap data can be fetched separately.
In pictures
How it works
- Ingest. Resolves each photo's camera and capture time, and flags unreadable files and unset clocks.
- Quality. Scores sharpness, brightness and night shots, and groups near-duplicates.
- Detect. Finds animal, person and vehicle boxes with MegaDetector.
- Classify. Labels each animal with SpeciesNet's top species, rolling up when the model is unsure.
- Events. Groups each camera's bursts into sightings and counts animals per species.
- Report. Species totals, activity by hour, camera health, charts and one HTML page.
Where to look in the code
README sections
- Overview (opens in a new tab) The problem and what the pipeline does
- Detect and classify (opens in a new tab) How the two open models are used
- Events (opens in a new tab) How bursts of photos become sightings
- Resuming after a crash (opens in a new tab) How every stage checkpoints
- Quickstart (opens in a new tab) Run the demo yourself
- Limitations (opens in a new tab) What it does not do
Files
- src/camera_trap_pipeline/detect.py (opens in a new tab) Detection
- src/camera_trap_pipeline/events.py (opens in a new tab) Sightings from bursts
- src/camera_trap_pipeline/atomic_io.py (opens in a new tab) Crash-safe writes
- tests (opens in a new tab) Test suite
- Automated checks (opens in a new tab) lint, type checks and tests on every push