Skip to content

Repository files navigation

This project is developed as part of Google Summer of Code 2026,under the DeepForest project (WeeCology).

Recovering Bird Annotations from Historical Airborne Imagery

Prototype for recovering ML-ready annotations from 18,304 historical bird survey screenshots where colored dots were baked directly into images by a point-counting tool. No coordinate data was saved. This prototype extracts dot positions, maps them to original high-resolution photographs, and produces DeepForest-compatible training data.

Data source: twi-aviandata.s3.amazonaws.com (Gulf of Mexico avian monitoring, 2010-2021, post-Deepwater Horizon)


About This Work

This prototype was built over 1.5 months with guidance from the open-source community and past DeepForest contributors who guided me through the open-source contribution process and research. Before writing any pipeline code, I spent two weeks studying the data — mapping 533K files in the S3 bucket, analyzing 49,204 CSV rows across 60 columns, downloading and measuring 25 diverse images, and testing existing models (SAM 3, DeepForest, GroundingDINO) to understand what was feasible. The pipeline went through multiple detector versions, four training experiments, and six approaches that were tested and abandoned. Every failure is documented with root cause analysis. The biggest lesson: study the data before building. 40% of my time was measurement and analysis. Every measured parameter directly informed a pipeline design decision. Detection accuracy jumped from 44% (first version, guessed parameters) to 70.8% (final version, measured parameters) without changing the fundamental approach.


Pipeline Output

The Problem: Annotations Baked Into Screenshots

Study Images

Four study images spanning the difficulty range. Left: screenshots with colored dots baked in by the counting tool. Right: original high-resolution photographs (no annotations). The pipeline recovers dot positions from the left and maps them to coordinates on the right.

Dataset Analysis (49,204 Rows)

CSV Analysis

LAGU (Laughing Gull) dominates at 855K birds. Median image has 61 birds. 18 annotators across 7 years and 5 Gulf Coast states. Every number here informed a pipeline parameter.

Measured Dot Properties

Dot Properties

Dot diameter 8.0px median, 6 distinct annotation colors, circularity 0.57. Measured from 1,199 candidate dots across all study images. These measurements set the detection thresholds — nothing was guessed.

Dots at 8x Zoom

Zoomed Dots

Individual annotation dots at 8x magnification showing actual pixel-level rendering. Red, yellow, green, cyan, blue, and magenta dots are clearly distinct from background at this scale.

Screenshot Decomposition

Decomposition

3-method consensus boundary detection (grey profile + Sobel edges + color variance) reliably separates the aerial photograph from the dialog box across all screenshot formats.

Detection Results (4 Study Images)

Detection

Detection on 4 study images (deliberately hard cases): D: 62%, B: 69%, A: 51%, C: 48%. Left: detected dots overlaid on aerial. Right: expected vs available vs selected per species. Batch of 30 random images achieves 70.8% overall.

Validation: Are These Real Dots?

Validation Grid

50 detected dots at 6x zoom from Image D. Top rows (high score): clearly real annotation dots with bright red centers. Bottom rows (low score): includes text watermark false positives ("17", "7Ma", etc.) — this is exactly why the text filter was disabled. Birds sitting in colony rows look like text to the algorithm.

Spatial Distribution

Spatial

Detected dots spread across aerial images, not clustered in one area. Coverage ranges from 52-92% of the 5x5 spatial grid per image.

Coordinate Mapping (Screenshot to Original)

Mapping

Left: dots on screenshot. Right: dots mapped to original high-resolution image. D and C use SIFT homography (0.5px accuracy). B and A use uniform height-based scaling (fallback when SIFT fails).

Mapped Dots Verification (Zoomed)

Zoom Verify

Top 10 mapped dots on original image at high zoom. Red crosshairs mark the mapped center. Bounding boxes show the annotation region. Birds visible at mapped locations.

Exported Dataset

Dataset Overview

3,915 recovered annotations across 21 species in DeepForest CSV format. Species distribution, score distribution, per-image counts, and mapping method breakdown.

Training Experiment: Full Circle

Full Circle

The complete pipeline story on one image: (1) corrupted screenshot with baked-in dots, (2) 64/93 dots recovered at 69% accuracy,(3) pretrained DeepForest finds 0 high-confidence detections (max score 0.23 — effectively blind on aerial data), (4) fine-tuned model — this panel shows the bfloat16-corrupted run (300 false detections at score 1.0). Root cause identified and fixed in subsequent experiments. See training analysis.

Training Experiment: SIFT-Only (Root Cause Fix)

SIFT Only

Training only on SIFT-mapped images (0.5px position accuracy, 920 annotations) produced the only improvement over pretrained: +29% max score, 0 to 1 high-confidence detection. This confirmed that position accuracy — not data quantity — drives training quality. With 76% fewer annotations but accurate positions, the model improved. With the full dataset (including ~30px position errors), it got worse.

Results

Metric Value
Images processed 34 (0 crashes)
Detection accuracy 70.8%
Precision 98.3%
False positive rate 1.7%
Annotations recovered 3,915
Species detected 21
SIFT mapping success 57% (0.5px error)
SAM 3 habitat classification 97%
Scene captions generated 34
Processing speed 11 sec/image
Estimated full dataset recovery ~340,000 annotations

What didn't work (and why)

Approach Result
OCR on dialog box 4-15% precision
Dialog color clusters 8% accuracy
Narrow HSV bins 44% accuracy
Text watermark filter Removed real dots
Training on full dataset 0 high-conf detections
Species-aware boxes Made it worse

Pipeline

Screenshot → Decompose → Detect Dots → Validate → Map → Export

  1. Screenshot Decomposition — 3-method consensus boundary detection
  2. Dot Detection — Wide HSV bins, vegetation-adaptive thresholds, count-guided selection from CSV
  3. Validation — 98.3% of detected dots land on high-saturation pixels
  4. Coordinate Mapping — SIFT homography (0.5px) with uniform fallback (height-based)
  5. SAM 3 Integration — Bird validation, habitat classification, scene captioning
  6. Export — DeepForest-compatible CSV with train/test split

Architecture

flowchart TB
    subgraph INPUTS["📥 INPUTS"]
        SS["🖥️ Corrupted Screenshot<br/>Dots baked into pixels"]
        OR["📷 Original Photograph<br/>Clean high-resolution"]
        CSV["📊 CSV Ground Truth<br/>49,204 rows × 60 cols<br/>Per-species counts"]
    end

    subgraph STAGE1["Stage 1: Screenshot Decomposition"]
        GP["Grey Profile"]
        SE["Sobel Edges"]
        CV["Color Variance"]
        GP & SE & CV --> MC["3-Method Consensus<br/>Median Boundary"]
        MC --> AE["Aerial Region Extracted"]
        MC --> DI["Dialog Region"]
    end

    subgraph STAGE2["Stage 2: Annotation Extraction"]
        HSV["HSV Segmentation<br/>6 Color Channels<br/>Wide Bins"]
        VB["Vegetation Boost<br/>Green S+50 when<br/>coverage >25%"]
        CC["Connected Components<br/>+ Distance Transform<br/>Cluster Splitting"]
        HSV --> VB --> CC
        CC --> DOTS["Detected Dot<br/>Positions + Colors"]
    end

    subgraph STAGE3["Stage 3: Species Assignment"]
        RO["Rank-Order Matching<br/>Largest color → Most abundant species<br/>CSV counts as ground truth"]
    end

    subgraph STAGE4["Stage 4: Coordinate Recovery"]
        SIFT["SIFT + RANSAC<br/>2000 keypoints<br/>Lowe ratio 0.75"]
        UNI["Uniform Fallback<br/>Height-ratio scaling<br/>scale_y for both axes"]
        SIFT -->|"≥10 matches"| GOLD["🥇 GOLD<br/><1px error"]
        SIFT -->|"<10 matches"| UNI
        UNI --> SILVER["🥈 SILVER / 🥉 BRONZE<br/>5-30px error"]
    end

    subgraph STAGE5["Stage 5: Cross-Validation"]
        SAM["SAM 3<br/>Text prompt: 'bird'"]
        IOU["IoU ≥0.05 +<br/>Distance ≤100px<br/>Matching"]
        HAB["Habitat Classification<br/>5 prompts × all images"]
        SAM --> IOU
        SAM --> HAB
    end

    subgraph STAGE6["Stage 6: Export"]
        DF["DeepForest CSV<br/>xmin, ymin, xmax,<br/>ymax, label, score"]
        SPLIT["Train/Test Split<br/>by Colony"]
        META["Quality Metadata<br/>Tier + Error + Species"]
        DF --> SPLIT
        DF --> META
    end

    subgraph TRAINING["🔬 Training Pipeline"]
        BIN["Stage 1: Binary<br/>All → 'Bird'<br/>GOLD only"]
        MIX["Stage 2: Binary<br/>GOLD + SILVER"]
        SPE["Stage 3: Species<br/>Top 5 labels"]
        RET["DeepForest RetinaNet<br/>lr=1e-4, focal loss<br/>bfloat16 disabled"]
        BIN --> MIX --> SPE
        SPE --> RET
    end

    subgraph OUTPUTS["📤 OUTPUTS"]
        ANN["3,915 Annotations<br/>21 Species"]
        MOD["Fine-tuned<br/>Bird Detector"]
        HAB2["Habitat Data<br/>97% classified"]
        CAP["Scene Captions<br/>34 generated"]
    end

    SS --> STAGE1
    AE --> STAGE2
    CSV --> STAGE3
    DOTS --> STAGE3
    RO --> STAGE4
    OR --> STAGE4
    GOLD & SILVER --> STAGE5
    GOLD & SILVER --> STAGE6
    IOU --> STAGE6
    HAB --> HAB2
    STAGE6 --> TRAINING
    TRAINING --> MOD
    STAGE6 --> ANN
    STAGE5 --> CAP
Loading

Key Findings

  • CSV ground truth is 100% accurate — OCR abandoned after testing
  • Wide HSV bins outperform narrow and adaptive approaches
  • Birds in colony rows resemble text — text filter disabled
  • Uniform scale_x is wrong — use scale_y for both axes
  • bfloat16 from SAM 3 silently corrupts DeepForest training
  • Position accuracy matters more than box size or data quantity
  • Full list: docs/learnings.md
  • Training details: docs/training_analysis.md

Repository Structure

notebook/prototype_v1.ipynb — Complete prototype, 23 sections, runs in Colab results/ — All output figures, metrics (JSON), annotations (CSV) docs/learnings.md — 21 documented learnings docs/training_analysis.md — 4 training experiments with root cause analysis

Quick Start

Open notebook/prototype_v1.ipynb in Google Colab. Set runtime to T4 GPU. Run all cells top to bottom (~45 minutes).

Dataset

Source: twi-aviandata.s3.amazonaws.com — 18,304 annotated screenshots, 49,204 CSV rows, 102 species, 18 annotators, 442 colonies, 7 years (2010-2021), 5 Gulf Coast states.

Full list of learnings: docs/learnings.md

Training experiment details: docs/training_analysis.md

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages