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.
147 lines
6.4 KiB
Markdown
147 lines
6.4 KiB
Markdown
# Installation
|
||
|
||
<sub>[← zurück zum Überblick](../README.md) · [alle Kapitel](README.md)</sub>
|
||
|
||
Zwei Wege zum selben Ziel. **Mit Docker** braucht es einen Befehl und keine
|
||
Python-Umgebung; **ohne Docker** sieht man mehr und kann einzelne Teile
|
||
austauschen.
|
||
|
||
## Welcher Weg ist meiner?
|
||
|
||
Vogelalbum besteht aus zwei Teilen, die getrennt laufen können: der **Sammlung**
|
||
(Django, zeigt Arten, XP und Abzeichen) und der **Erkennung** (schaut in die
|
||
Kamera und meldet Sichtungen). Daraus ergeben sich drei sinnvolle Aufbauten —
|
||
und für jeden gibt es genau eine Datei:
|
||
|
||
| Dein Fall | Datei | Was läuft |
|
||
|---|---|---|
|
||
| **Eine Kamera im Garten, ein Rechner im Keller.** Der Normalfall, und der richtige Anfang. | `docker-compose.heim.yml` | Sammlung **und** Erkennung auf einer Maschine |
|
||
| **Die Sammlung soll öffentlich erreichbar sein**, die Kamera bleibt zu Hause. | `docker-compose.yml` | nur die Sammlung, mit nginx für die Fotos |
|
||
| **Der Rechner mit Sicht auf die Kamera** liefert an eine Sammlung woanders. | `docker-compose.detector.yml` | nur die Erkennung |
|
||
|
||
Die letzten beiden gehören zusammen: Sie sind dieselbe Anlage, aufgeteilt auf
|
||
zwei Orte. So läuft auch <https://vogelalbum.gaertner.onl> — Sammlung bei einem
|
||
Hoster, Erkennung im Heimnetz.
|
||
|
||
🔑 **Nach außen muss dafür kein Port offen sein.** Die Verbindung geht nur in
|
||
eine Richtung: Die Erkennung meldet ausgehend an die Sammlung, die Sammlung
|
||
erreicht die Kamera nie. Kein Portforwarding, kein Tunnel, kein DynDNS.
|
||
|
||
⚠️ **Wo die Erkennung laufen kann:** `ai-edge-litert` gibt es als fertiges
|
||
Wheel für **x86_64 und arm64**. Ein **Pi Zero trägt sie nicht** — dem fehlt
|
||
nicht das Wheel, sondern die Rechenleistung; er ist die *Kamera*seite, siehe
|
||
[pi/README.md](../pi/README.md).
|
||
|
||
### Getestet auf
|
||
|
||
Zwei Geräte, wie sie in vielen Hausnetzen stehen. Beide mit dem Schnellstart
|
||
oben eingerichtet, aus einem frischen Klon und mit leerem Build-Zwischenspeicher:
|
||
|
||
| | **Intel N100** | **Raspberry Pi 4 Model B** |
|
||
|---|---|---|
|
||
| | 16 GB, Debian, x86_64 | 4 GB, Ubuntu 26.04, aarch64 |
|
||
| Images bauen (einmalig) | 69 s | 467 s (knapp 8 min) |
|
||
| Sammlung erreichbar nach | 5 s | 49 s |
|
||
| **Ein Bild bestimmen** | **~30 ms** | **42 ms** (Median aus 18 Messungen, 35–53 ms) |
|
||
| Arbeitsspeicher im Betrieb | — | 1,1 von 3,7 GB |
|
||
| Temperatur unter Last | — | 54 °C, keine Drosselung |
|
||
|
||
🔑 **Der Pi 4 langweilt sich dabei.** Bei 4 Bildern pro Sekunde und
|
||
`--classify-every=2` stehen rund **500 ms** je bestimmtem Bild zur Verfügung —
|
||
er braucht 42. Er könnte also jedes Bild bestimmen statt jedes zweite und wäre
|
||
immer noch bei einem Sechstel. Dass ARM hier so gut mithält, liegt an den
|
||
int8-quantisierten Modellen; gerechnet hatten wir mit einem Vielfachen.
|
||
|
||
Der Preis auf dem Pi sind die acht Minuten Bauzeit und die knappe Minute bis
|
||
zur ersten Seite. Beides fällt genau einmal an.
|
||
|
||
⚠️ **Ungetestet:** Raspberry Pi 5 (sollte schneller sein), Pi 4 mit nur 2 GB,
|
||
und 32-Bit-Systeme (dort gibt es kein `ai-edge-litert`-Wheel — Raspberry Pi OS
|
||
muss die 64-Bit-Ausgabe sein). Rückmeldungen zu anderer Hardware sind
|
||
willkommen, gern als Issue.
|
||
|
||
Wer gar kein Docker will: [ohne Docker](#schnellstart-ohne-docker) weiter
|
||
unten. Und wer nur schauen will, wie es aussieht, braucht nicht einmal eine
|
||
Kamera — siehe [Ohne Kamera ausprobieren](#ohne-kamera-ausprobieren).
|
||
|
||
## Schnellstart mit Docker
|
||
|
||
Der kürzeste Weg — Sammlung und Erkennung auf einer Maschine, ohne venv, ohne
|
||
Modelle von Hand, ohne systemd:
|
||
|
||
```bash
|
||
git clone https://gitea.gaertner.onl/christian/vogelalbum.git && cd vogelalbum
|
||
cp .env.beispiel .env # VOGELALBUM_SOURCE und ein Token eintragen
|
||
docker compose -f docker-compose.heim.yml up -d
|
||
```
|
||
|
||
Der erste Start baut beide Images (rund eine Minute) und legt den Artenkatalog
|
||
an: **148 Arten mit Steckbriefen und 15 Abzeichen.** Die Sammlung steht danach
|
||
sofort; die Referenzfotos aus Wikipedia holt der Container im Hintergrund nach
|
||
und tropfen über die nächsten Minuten ein.
|
||
|
||
Danach läuft die Sammlung auf <http://localhost:8000> und der Detector schaut
|
||
in die Kamera. Zwei Zeilen in der `.env` müssen stimmen:
|
||
|
||
| Variable | was rein muss |
|
||
|---|---|
|
||
| `VOGELALBUM_SOURCE` | Stream-URL der Kamera, z.B. `http://vogelkamera.local:8080/stream` |
|
||
| `VOGELALBUM_INGEST_TOKEN` | ein selbst ausgedachtes Geheimnis, `openssl rand -base64 32` |
|
||
|
||
Alles andere hat brauchbare Vorgaben; den Django-`SECRET_KEY` erzeugt der
|
||
Container beim ersten Start selbst und legt ihn aufs Volume.
|
||
|
||
Noch keine Kamera? Die Kameraseite steht in **[pi/README.md](../pi/README.md)** —
|
||
ein Raspberry Pi Zero W mit Kameramodul reicht. Alternativ ein ESP32-S3 mit
|
||
Kameramodul: **[esp32cam/README.md](../esp32cam/README.md)**, deutlich billiger
|
||
und mit externer Antenne, was der Bildrate mehr hilft als jede Auflösung.
|
||
|
||
```bash
|
||
docker compose -f docker-compose.heim.yml logs -f detector # was sieht er?
|
||
docker compose -f docker-compose.heim.yml down # anhalten
|
||
```
|
||
|
||
Sammlung und Rohbilder liegen in Docker-Volumes und überleben ein
|
||
`up --build`. Wer die Sammlung öffentlich hosten und nur die Erkennung zu
|
||
Hause laufen lassen will, nimmt die beiden anderen Dateien aus der
|
||
[Tabelle oben](#welcher-weg-ist-meiner): `docker-compose.yml` beim Hoster,
|
||
`docker-compose.detector.yml` zu Hause. Das Deployment der Sammlung steht in
|
||
[Betrieb](betrieb.md).
|
||
|
||
## Schnellstart ohne Docker
|
||
|
||
Voraussetzungen: Python 3.11+, rund 500 MB Platte, eine Kamera die MJPEG,
|
||
RTSP oder Einzelbilder liefert.
|
||
|
||
```bash
|
||
git clone https://gitea.gaertner.onl/christian/vogelalbum.git && cd vogelalbum
|
||
python3 -m venv venv
|
||
./venv/bin/pip install -r requirements-detector.txt -r requirements-web.txt
|
||
./scripts/fetch_models.sh # ~10 MB, liegen nicht im Repo
|
||
./scripts/fetch_testdata.sh # drei Beispielfotos, optional
|
||
|
||
cd web
|
||
../venv/bin/python manage.py migrate
|
||
../venv/bin/python manage.py seed_dex # 148 Arten, 15 Abzeichen
|
||
../venv/bin/python manage.py fetch_reference_images # Wikipedia-Fotos, ~5 min
|
||
../venv/bin/python manage.py runserver 0.0.0.0:8000
|
||
```
|
||
|
||
Dann in einem zweiten Terminal:
|
||
|
||
```bash
|
||
./venv/bin/python -m detector watch --source "http://<kamera>:8080/stream"
|
||
```
|
||
|
||
### Ohne Kamera ausprobieren
|
||
|
||
```bash
|
||
cd web
|
||
../venv/bin/python manage.py demo_data # 21 Tage Beispieldaten
|
||
../venv/bin/python manage.py demo_data --clear
|
||
```
|
||
|
||
Die Demo-Sichtungen benutzen die Wikipedia-Referenzfotos, sind also klar als
|
||
Attrappe erkennbar. **Vor dem Echtbetrieb `--clear` laufen lassen**, sonst
|
||
mischen sich Demo- und Kameradaten.
|