# Fahrzeug- und Objekt-Erkennungssystem ![Vehicle Counter – Smart Traffic Monitoring mit ESP32-CAM](pictures/vehicle-counter.png) [![Video Demo](https://img.youtube.com/vi/j94-OHGflT8/maxresdefault.jpg)](https://www.youtube.com/watch?v=j94-OHGflT8) Eine webbasierte Anwendung zur Echtzeit-Objekterkennung und -Verfolgung mittels YOLOv11. Die Anwendung unterstützt sowohl Live-Webcam-Streams als auch die Verarbeitung hochgeladener Videodateien. ## Funktionen - **Webcam-Erkennung**: Echtzeit-Objekterkennung über die Webcam - **Video-Upload**: Hochladen und Verarbeiten von Videodateien mit Objekterkennung - **Objekt-Tracking**: Persistente Verfolgung von Objekten mit eindeutigen IDs über Frames hinweg - **Visuelle Markierungen**: Bounding Boxes und Labels für erkannte Objekte - **Browser-basiert**: Einfacher Zugriff über den Webbrowser ## Voraussetzungen - Python 3.12 oder höher - **NVIDIA-Grafikkarte mit CUDA-Unterstützung** – für die Echtzeit-Erkennung erforderlich (siehe [Hardware & CUDA](#hardware--cuda)) - **[ESP32-CAM](https://mygopage.de/s/xkKwJF)** als Live-Quelle, die einen MJPEG-Stream im Netzwerk bereitstellt (siehe [Kamera / Livestream (ESP32-CAM)](#kamera--livestream-esp32-cam)) - **MQTT-Broker** (*optional*) zum Empfang der Zähl-Events (z. B. [Mosquitto](https://mosquitto.org/)); per `MQTT_ENABLED=false` abschaltbar (siehe [MQTT / Zähl-Events](#mqtt--zähl-events)) - Die YOLO-Modelle werden beim ersten Start automatisch von Ultralytics geladen (Internetverbindung erforderlich) > ⚠️ **Wichtig:** Für die flüssige Live-Erkennung wird eine **NVIDIA-GPU mit CUDA** benötigt. Ohne CUDA läuft die Inferenz auf der CPU und ist für Echtzeit-Streams zu langsam. ## Installation 1. Repository klonen oder herunterladen 2. Erforderliche Python-Pakete installieren: ```bash pip3 install flask opencv-python numpy ultralytics requests paho-mqtt python-dotenv ``` 3. **CUDA-fähiges PyTorch installieren** (für GPU-Beschleunigung). Die passende Variante richtet sich nach der installierten CUDA-Version, z. B. für CUDA 12.x: ```bash pip3 install torch --index-url https://download.pytorch.org/whl/cu121 ``` Prüfen, ob die GPU erkannt wird: ```bash python3 -c "import torch; print(torch.cuda.is_available())" ``` Gibt der Befehl `True` aus, wird die NVIDIA-GPU genutzt und FP16-Inferenz automatisch aktiviert. 4. Die YOLO-Modelle (`yolo11s.pt` für Video-Upload, `yolo11n.pt` für die Webcam) müssen **nicht** manuell beschafft werden – Ultralytics lädt sie beim ersten Start automatisch herunter (Internetverbindung erforderlich) und legt sie im Hauptverzeichnis ab. ## Verwendung ### Anwendung starten ```bash python3 app.py ``` Die Anwendung ist dann unter `http://localhost:8080` erreichbar. ### Dauerbetrieb mit supervisord (24/7) Für den Dauerbetrieb (automatischer Start, Neustart bei Absturz) eignet sich [supervisord](http://supervisord.org/). Beispiel-Konfiguration unter `/etc/supervisor/conf.d/vehicle-counter.conf`: ```ini [program:vehicle-counter] directory=/pfad/zum/vehicle-counter command=/pfad/zur/python app.py user=DEIN_USER autostart=true autorestart=true startsecs=5 stopwaitsecs=10 stdout_logfile=/var/log/vehicle-counter.log stderr_logfile=/var/log/vehicle-counter-error.log stdout_logfile_maxbytes=20MB stderr_logfile_backups=5 environment=PYTHONUNBUFFERED="1" ``` > ⚠️ **`directory=` muss auf das Projektverzeichnis zeigen!** Sonst findet die App > die `.env` (Kamera/MQTT) und `counting_line.json` nicht und fällt auf Defaults > zurück. Aktivieren und steuern: ```bash sudo supervisorctl reread # neue Config einlesen sudo supervisorctl update # Programm hinzufügen/starten sudo supervisorctl restart vehicle-counter # nach Code-Updates neu starten sudo supervisorctl status vehicle-counter # Status prüfen tail -f /var/log/vehicle-counter.log # Logs ansehen ``` Nach einem `git pull` mit Code-Änderungen ist ein `restart` nötig; reine Template-/Frontend-Änderungen werden dank `TEMPLATES_AUTO_RELOAD` auch ohne Neustart übernommen. ### Konfiguration (.env) Kamera-, MQTT- und Inferenz-Einstellungen werden über Umgebungsvariablen gesteuert. Am einfachsten kopierst du die mitgelieferte Vorlage und passt die Werte an – die `.env` wird beim Start **automatisch geladen** (`python-dotenv`): ```bash cp .env.example .env # anschließend .env im Editor öffnen und die Werte anpassen ``` Die wichtigsten Einstellungen: ```bash export CAMERA_URL="http://CAMERA-IP:81/stream" # MJPEG-Stream der Kamera export MQTT_ENABLED="true" # "false" = ohne Broker starten export MQTT_HOST="127.0.0.1" # Adresse des MQTT-Brokers export MQTT_PORT=1883 export MQTT_TOPIC="vehiclecounter/meine-kamera" # Basis-Topic der Events export CAMERA_ID="meine-kamera" # Kennung in den Events ``` Eine vollständige, kommentierte Liste aller Variablen steht in [`.env.example`](.env.example). > 💡 **Ohne MQTT-Broker?** Setze `MQTT_ENABLED="false"` – dann startet die App > ganz normal, zählt und streamt, sendet aber keine MQTT-Events. Ideal zum > Ausprobieren ohne Broker-Setup. (Auch mit `true` startet die App übrigens, > wenn der Broker gerade nicht erreichbar ist – sie verbindet sich dann später.) > ⚠️ Beim Betrieb über einen Prozess-Manager (z. B. **supervisord**) muss das > Arbeitsverzeichnis auf das Projekt zeigen (`directory=/pfad/zum/projekt`), > sonst wird die `.env` nicht gefunden und es greifen die Defaults. > Die `.env` ist per `.gitignore` ausgeschlossen und gehört nicht ins Repo. ### Webcam-Erkennung 1. Öffnen Sie `http://localhost:8080` im Browser 2. Klicken Sie auf "Start Webcam Detection" 3. Die Webcam wird aktiviert und Objekte werden in Echtzeit erkannt und markiert 4. Jedes Objekt erhält eine Track-ID und Klassenbeschriftung ### Video-Upload 1. Öffnen Sie `http://localhost:8080` im Browser 2. Wählen Sie eine Videodatei über das Upload-Formular aus 3. Klicken Sie auf "Upload Video" 4. Das Video wird verarbeitet und mit Objekterkennungen angezeigt ## Projektstruktur ``` . ├── app.py # Haupt-Flask-Anwendung ├── yolo11s.pt # YOLOv11-Modell (wird autom. geladen, nicht versioniert) ├── yolo11n.pt # YOLOv11-Nano-Modell für Webcam (autom. geladen) ├── templates/ # HTML-Templates │ ├── index.html # Startseite │ ├── webcam.html # Webcam-Anzeige │ └── play_video.html # Video-Wiedergabe ├── uploads/ # Hochgeladene Videos (automatisch erstellt) └── highway1.mp4 # Beispielvideo ``` ## Technische Details ### Kamera / Livestream (ESP32-CAM) In diesem Beispiel dient eine **ESP32-CAM** als Live-Quelle. Sie stellt einen **MJPEG-Stream** im Netzwerk bereit, den die Anwendung abgreift, mit YOLO auswertet und an die Browser-Viewer weiterverteilt. **📷 Hardware-Empfehlung (Outdoor-Setup):** | Komponente | Zweck | | ---------- | ----- | | [ESP32-CAM](https://mygopage.de/s/xkKwJF) | Die Kamera selbst – günstig (~5–10 €), bei Diebstahl/Defekt kein großer Verlust | | [Regenwasserdichte Box](https://mygopage.de/s/brkpeY) | Wetterschutz für den Außeneinsatz – Kamera **und** Powerbank passen hinein | | [Powerbank](https://mygopage.de/s/2S7hhr) | Günstige Stromversorgung, macht die Kamera netzunabhängig | > *Affiliate-Links – beim Kauf darüber unterstützt du das Projekt ohne Mehrkosten für dich.* - Die Stream-Adresse wird über die Umgebungsvariable `CAMERA_URL` gesetzt. Typisch für die ESP32-CAM sind Port `81` und der Pfad `/stream` – `CAMERA-IP` durch die IP-Adresse der eigenen Kamera ersetzen: ```bash export CAMERA_URL="http://CAMERA-IP:81/stream" ``` - Es wird **eine einzige Verbindung** zur ESP32-CAM aufgebaut und das Bild an beliebig viele Zuschauer verteilt (Fan-out). So wird der begrenzte Stream-Slot der ESP32-CAM nicht durch jeden Browser blockiert. - Mit `GRABBER_ALWAYS_ON=1` läuft der Grabber rund um die Uhr und zählt auch dann, wenn niemand zuschaut. Bei `0` (Standard) verbindet er sich nur, solange ein Browser den Stream betrachtet – das gibt den ESP32-Slot wieder frei. > 💡 Statt einer ESP32-CAM kann über `CAMERA_URL` auch jede andere MJPEG-/HTTP- > Stream-Quelle eingebunden werden. ### MQTT / Zähl-Events Jede erkannte Linienüberquerung wird als **MQTT-Event** veröffentlicht. Dafür wird ein **MQTT-Broker** benötigt (z. B. [Mosquitto](https://mosquitto.org/)). So lassen sich die Zähldaten z. B. über **n8n** weiterverarbeiten und in einer Datenbank wie **NocoDB** ablegen. - Die Events werden auf dem Topic `{MQTT_TOPIC}/crossing` mit **QoS 1** (nicht retained) publiziert. - Zusätzlich gibt es ein **Status-/Availability-Topic** `{MQTT_TOPIC}/status` (retained): Beim Verbinden sendet die App `online` (Birth-Message), bei einem Verbindungsabbruch publiziert der Broker automatisch `offline` (Last Will / LWT). So lässt sich jederzeit erkennen, ob der Counter läuft. - Das Payload ist JSON, z. B.: ```json { "event": "crossing", "camera": "cam1", "source": "webcam", "type": "car", "track_id": 42, "ts": "2026-06-01T12:34:56+02:00" } ``` - Konfiguriert wird der Broker über Umgebungsvariablen: | Variable | Standard | Beschreibung | | -------------- | ---------------------- | ------------------------------------ | | `MQTT_ENABLED` | `true` | MQTT komplett ein-/ausschalten | | `MQTT_HOST` | `127.0.0.1` | Adresse des MQTT-Brokers | | `MQTT_PORT` | `1883` | Broker-Port | | `MQTT_USER` | – | Benutzername (optional) | | `MQTT_PASS` | – | Passwort (optional) | | `MQTT_TOPIC` | `vehiclecounter/cam1` | Basis-Topic der Events | | `CAMERA_ID` | `cam1` | Kamera-Kennung im Payload | > ℹ️ Die Verbindung zum Broker erfolgt asynchron. Ist der Broker nicht > erreichbar, startet die Anwendung trotzdem – es werden dann lediglich keine > Events übertragen. ### Hardware & CUDA Die Objekterkennung mit YOLOv11 ist rechenintensiv. Für die Echtzeit-Verarbeitung von Live-Streams wird daher eine **NVIDIA-Grafikkarte mit CUDA** benötigt. - **Mit NVIDIA-GPU (CUDA):** Die Inferenz läuft auf der Grafikkarte. Erkennt die Anwendung eine CUDA-fähige GPU, wird automatisch **FP16-Inferenz** aktiviert (per `YOLO_HALF` überschreibbar) – das halbiert den Speicherbedarf und erhöht die Bildrate spürbar. - **Ohne GPU (nur CPU):** Die Anwendung startet zwar, die Inferenz ist für Live-Streams jedoch zu langsam. Ein zusätzliches **Motion-Gate** sorgt dafür, dass YOLO nur bei tatsächlicher Bewegung im Bild ausgeführt wird, was die Last reduziert – ersetzt eine GPU aber nicht. Voraussetzungen für die GPU-Nutzung: - NVIDIA-Treiber + passende CUDA-Runtime - CUDA-fähiges PyTorch (siehe [Installation](#installation)) ### Verwendete Technologien - **Flask**: Web-Framework für Routing und Template-Rendering - **OpenCV**: Videobearbeitung und Frame-Manipulation - **Ultralytics YOLO**: YOLOv11-Modell für Objekterkennung und Tracking - **NumPy**: Array-Operationen für Bilddaten ### Verarbeitungs-Pipeline 1. **Frame-Erfassung**: Webcam oder Videodatei als Quelle 2. **Frame-Skipping**: Verarbeitung jedes 2. Frames zur Leistungsoptimierung 3. **Größenanpassung**: Alle Frames werden auf 1020x600 Pixel skaliert 4. **YOLO-Tracking**: Objekterkennung mit persistenten Track-IDs 5. **Annotation**: Zeichnen von Bounding Boxes und Labels 6. **Streaming**: Übertragung als MJPEG-Stream an den Browser ### Objekterkennung - Erkennt verschiedene Objektklassen (abhängig vom YOLO-Modell) - Vergibt eindeutige Track-IDs für jedes Objekt - Beschriftung im Format: `{Track-ID} - {Klassenname}` - Grüne Bounding Boxes um erkannte Objekte - Magenta-farbene Textbeschriftungen ## Leistungsoptimierung - **Frame-Skipping**: Nur jeder 2. Frame wird verarbeitet, um CPU-Last zu reduzieren - **Feste Auflösung**: Einheitliche Größe von 1020x600 Pixel für alle Frames - **Effizientes Streaming**: JPEG-Kompression für Frame-Übertragung ## Einschränkungen - Keine Validierung der Upload-Dateigröße - Keine automatische Bereinigung hochgeladener Dateien - Feste Frame-Dimensionen (1020x600) - Keine Fehlerbehandlung bei Webcam-Zugriffsproblemen ## Hinweise - Bei der ersten Verwendung kann das Laden des YOLO-Modells einige Sekunden dauern - Die Erkennungsgenauigkeit hängt vom verwendeten YOLO-Modell ab - Frame-Skipping kann bei sehr schnell bewegten Objekten zu Erkennungslücken führen - Hochgeladene Videos werden im Ordner `uploads/` gespeichert und müssen manuell gelöscht werden ## Lizenz Projekt basiert auf Ressourcen von [Pyresearch](https://pyresearch.org/)