Files
vogelalbum/docs/kamera.md
T
christian c11fe9ab04 Vogelalbum 1.0.0
Eine Kamera am Vogelhaus, ein Rechner der erkennt wer da war — und eine
Sammlung, die sich von allein fuellt.

Zwei neuronale Netze: eines findet den Vogel im Bild, eines bestimmt die
Art. 148 heimische Arten, auf Deutschland eingeschraenkt und neu normiert —
ohne diese Einschraenkung wird aus einer Kohlmeise eine nordamerikanische
Schwesterart. Daraus entsteht ein Sammelalbum: nummerierte Seiten,
gefundene Arten in Farbe, fehlende als Schatten, dazu Erstfang, Punkte,
Stufen und 15 Abzeichen.

Laeuft vollstaendig auf eigener Hardware. Kein Cloud-Dienst, kein Konto,
keine Telemetrie; die Bilder verlassen das eigene Netz nicht.

Zwei getrennt deploybare Teile: die Sammlung als Django-Anwendung, die
Erkennung als eigener Dienst. Der Erkennungs-Dienst fragt selbst an und
braucht deshalb weder eine erreichbare Adresse noch einen offenen Port —
er laeuft hinter einem gewoehnlichen Router.

Dabei: Firmware fuer Raspberry Pi und ESP32-S3, Anbindung an Home
Assistant ueber MQTT, Oberflaeche auf Deutsch und Englisch, Einstellungen
je Kamera aus dem Browser, und ein Weg fuer Fotos von unterwegs.

AGPL-3.0.
2026-10-15 14:30:02 +00:00

8.3 KiB
Raw Blame History

Die Kamera anschließen

← zurück zum Überblick · alle Kapitel

Vogelalbum braucht von der Kamera nur einen Stream. Hier steht, welche Formen davon gelesen werden, wie man die Schwellwerte einstellt und — die Frage, an der ein Aufbau wirklich scheitert — wie groß ein Vogel im Bild sein muss.

Der Aufbau der Kameraseite selbst steht getrennt: Raspberry Pi oder ESP32-S3.

Noch keine Kamera aufgebaut? Es gibt zwei fertige Kameraseiten, beide mit denselben Pfaden — der Detector merkt den Unterschied nicht:

  • pi/README.md — Raspberry Pi mit Kameramodul, MJPEG-Server als Dienst (pi/vogelkamera.py). Die bessere Optik.
  • esp32cam/README.md — ESP32-S3 mit Kameramodul (esp32cam/). Ein Bruchteil des Preises, externe Antenne möglich, und /status liefert Bildrate, Funkstärke und Temperatur, ohne den Stream anzufassen.

Beide Anleitungen nennen die drei Dinge, die man dabei einmal falsch macht — zweiter Zuschauer, Hitze im Kasten, Bildrate am Licht statt an der CPU.

Der Detector spricht MJPEG, RTSP, Einzelbild-URLs und Ordner:

# MJPEG (mjpg-streamer, motion, picamera2-Beispielserver)
python -m detector watch --source "http://kamera.local:8080/stream"

# Einzelbild im Sekundentakt — genügsamer, für einen Nistkasten meist genug
python -m detector watch --source "http://kamera.local/snapshot.jpg" --interval 1

# RTSP (braucht ffmpeg auf dem Host)
python -m detector watch --source "rtsp://kamera.local:8554/cam"

# Ordner mit Bildern, zum Ausprobieren ohne Kamera
python -m detector watch --source ./testbilder

Mit Anbindung an die Web-App:

python -m detector watch \
  --source "http://kamera.local:8080/stream" \
  --api http://127.0.0.1:8000 \
  --token "$VOGELALBUM_TOKEN" \
  --save-to /var/lib/vogelalbum/rohdaten

--save-to schreibt Bild und JSON zusätzlich auf Platte. Das kostet fast nichts und ist später das Trainingsmaterial fürs eigene Modell.

Schwellwerte einstellen

Die Voreinstellungen passen zu unserer Kamera. An einer anderen gehören sie gemessen:

python -m detector tune --source "http://kamera.local:8080/stream"

Zeigt live den Anteil bewegter Pixel und die Bildhelligkeit. --motion-ratio gehört knapp über den Ruhepegel — hoch genug, dass Wind und Lichtwechsel nicht auslösen, niedrig genug für eine Blaumeise am Bildrand. Liegt der Ruhepegel ohnehin hoch, ist --gate detector die bessere Wahl.

Das ist aber nur die Bewegungsschwelle. Ob die Kamera überhaupt an der richtigen Stelle hängt, beantwortet detector karte — und zwar bevor man Tage auf den ersten Vogel wartet.

Abschaltung bei Dunkelheit

Eine Kamera ohne Infrarot liefert nachts ein schwarzes Bild. Es durch zwei neuronale Netze zu schicken kostet Strom und bringt nichts, deshalb pausiert der Detector von selbst.

Entschieden wird über die Bildhelligkeit, nicht über Sonnenauf- und -untergang. Das braucht keine Koordinaten und misst genau das, worauf es ankommt: ob man etwas sieht. Ein Futterhaus unter einer Straßenlaterne bleibt nutzbar, ein zugewachsenes ist schon vor Sonnenuntergang zu dunkel.

Zwischen Abschalt- und Einschaltschwelle liegt bewusst Abstand — ohne diese Hysterese flattert die Entscheidung in der Dämmerung im Sekundentakt.

Eine Infrarotkamera liefert nachts ein graues, aber helles Bild und läuft damit von selbst weiter. --nachtsicht ist nur nötig, wenn die Automatik danebenliegt.

Gemessen im Betrieb: statt rund 40 % eines Kerns bleiben nachts 9 %, und die gehen fast vollständig für das Dekodieren des MJPEG-Stroms drauf.

Dauerprotokoll

Sechs Minuten zuschauen beantwortet die Frage „übersehen wir Vögel?" nur für diese sechs Minuten. Über Tage beantwortet sie ein Protokoll:

python -m detector watch --source ... --protokoll /var/lib/vogelalbum/protokoll.csv

Geschrieben werden zwei Sorten Zeilen:

  • jede Erkennung ab --protokoll-ab (Standard 0.08, weit unter der Betriebsschwelle von 0.4) — auch die, die für eine Sichtung nicht gereicht hat. Genau daran sieht man, ob die Schwelle zu hoch steht oder die Vögel schlicht zu klein im Bild sind.
  • ein Lebenszeichen je Viertelstunde, immer, auch wenn nichts passiert ist. Diese Zeilen sind die wichtigeren: Ein Protokoll, das nur bei Erfolg schreibt, sieht bei einem Ausfall genauso aus wie bei einem ruhigen Tag.

Wie groß muss ein Vogel im Bild sein

Gemessen, indem ein echter Vogelausschnitt in verschiedenen Größen in ein Bild derselben Kamera montiert wurde:

Anteil am Bild Detektor-Score
15 % 0.93 ✅
10 % 0.77 ✅
5 % 0.77 ✅
3 % 0.23 ❌ unter der Schwelle
1 % 0.07 ❌

Die Grenze liegt bei rund 5 % der Bildfläche — bei 1280×720 also etwa 260×175 Pixel.

Aufschlussreich ist, was dabei nicht zusammenbricht: Die Artbestimmung liegt selbst bei 1 % Fläche noch bei 100 %. Der Engpass ist also nicht, die Art zu erkennen, sondern überhaupt zu merken, dass da ein Vogel ist. Für den Aufbau heißt das: näher heran schlägt höhere Auflösung.

Die 5 % sind allerdings kein fester Wert, sondern hängen am Hintergrund. Dieselbe Messung nach einem Umsetzen der Kamera — statt ruhigem Grund nun ein Baum im Wind hinter dem Futter — ergab erst ab 8 % eine zuverlässige Erkennung. Deshalb misst man an der eigenen Kamera nach, statt eine Zahl aus diesem README zu übernehmen. Genau dafür gibt es das nächste Kommando.

Hängt die Kamera richtig? (detector karte)

Die Größe ist nur die halbe Antwort. Die andere ist, wo im Bild der Vogel sitzt — und da gibt es Zonen, in denen der Detektor auch einen großen Vogel nicht findet.

python -m detector karte --source http://vogelhaus.local:8080/stream \
  --vogel testdata/amsel.jpg --anteil 0.08 --ziel karte.jpg

Ein echtes Vogelfoto wird mit weicher Maske über ein Raster von Positionen in aktuelle Bilder der eigenen Kamera montiert und jedes Mal durch den Detektor geschickt. Heraus kommt eine Ampel über dem eigenen Kamerabild — grün erkannt, rot nicht — plus dieselbe Karte als Tabelle und ein Satz, was zu tun ist.

Das beantwortet vor dem ersten echten Besuch, ob die Kamera richtig hängt. Ohne diese Karte wartet man Tage auf eine leere Sammlung und weiß danach immer noch nicht, ob keine Vögel kamen oder ob sie an der falschen Stelle im Bild saßen.

Am Vogelhaus in Herzogenrath sah das so aus:

Fuss y    x=0.18   x=0.32   x=0.46   x=0.60   x=0.74   x=0.88
  0.55    OK 0.84  -- 0.44  OK 0.67  OK 0.67  OK 0.44  -- 0.44
  0.65    OK 0.77  -- 0.44  OK 0.80  OK 0.56  -- 0.28  OK 0.62
  0.75    OK 0.67  -- 0.38  OK 0.80  OK 0.72  -- 0.38  OK 0.56
  0.85    OK 0.84  OK 0.67  OK 0.77  OK 0.84  OK 0.56  OK 0.72
  0.95    -- 0.38  -- 0.16  -- 0.38  OK 0.62  -- 0.23  -- 0.20

Die unterste Reihe fällt fast geschlossen durch — und genau dort steht ein Vogel, der auf dem Futterbrett landet, wenn die Kamera flach darüber hinweg schaut. Derselbe Vogel in derselben Größe zehn Prozent höher im Bild: 0.84.

Daraus die Bauregel, die für jedes Futterhaus gilt: die Landefläche gehört in die untere Bildmitte, nicht an den unteren Bildrand. Kamera so weit nach unten neigen, bis unter dem Futter noch Bild übrig ist.

Nachsehen, was angekommen ist

Nach den ersten Tagen ist die Frage nicht „läuft es", sondern „sehen wir Vögel, und taugen die Bilder etwas". Dafür gibt es eine Auswertung der Rohdaten:

python -m detector report /var/lib/vogelalbum/rohdaten
python -m detector report /var/lib/vogelalbum/rohdaten --kontaktbogen bogen.jpg

Sie misst je Sichtung nach, statt zu schätzen: Schärfe (Varianz der Laplace-Antwort, unter ~50 sichtbar verwackelt), Fläche des Vogels im Bild und Helligkeit.

Die Fläche ist dabei der wichtigste Wert. Ein Vogel, der unter 3 % des Bildes einnimmt, ist ein Fleck — daran ändert kein Schwellwert etwas, da muss die Kamera näher heran oder enger eingestellt werden. Die Auswertung sagt das ausdrücklich, wenn es auf mehr als ein Drittel der Sichtungen zutrifft.

Der Kontaktbogen legt alle Ausschnitte als ein Bild nebeneinander. Ob die Qualität reicht, sieht man damit in zehn Sekunden statt in sechzig einzeln geöffneten Dateien.