In diesem Tutorial lernst du, wie man mit dem ESP32-CAM Modul und YOLO, einem Deep-Learning-System zur Objekterkennung, Objekte erkennt und klassifiziert.
Ich führe dich durch den Aufbau eines Projekts, bei dem der ESP32-CAM Bilder aufnimmt, als Webserver fungiert und die Bilder zur Analyse an einen Computer sendet. Der Computer nutzt YOLO, um Objekte zu erkennen und zu klassifizieren. Du lernst, die Hardware zusammenzubauen, die Kamera zu konfigurieren und JPEG-Bilder über HTTP bereitzustellen.
Am Ende hast du eine funktionierende Weboberfläche, um Schnappschüsse deines ESP32-CAM anzusehen, sowie ein Objekterkennungssystem für 80 verschiedene Objekttypen.
Benötigte Teile
Im Folgenden findest du die Komponenten, die für den Aufbau des Projekts erforderlich sind. Anstelle des FTDI Programmers könntest du auch ein Programmier-Shield für den ESP32-CAM verwenden, aber ich empfehle den erstgenannten.

ESP32-CAM

FTDI USB-TTL Adapter

USB-Datenkabel

Arduino IDE
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Systemarchitektur
Das System, das wir bauen, besteht aus zwei Hauptkomponenten: 1) einem ESP32-CAM Modul, das Bilder aufnimmt und als Webserver fungiert, der die Bilder per WiFi sendet. 2) einem PC, auf dem das YOLO Objekterkennungssystem läuft. Es analysiert die Bilder und markiert die erkannten Objekte. Das folgende Diagramm gibt dir einen Überblick über die Systemarchitektur:

Das folgende Bild zeigt ein Beispiel für eine Erkennung durch das System. Auf meinem unordentlichen Schreibtisch konnte YOLO eine Tasse mit 88% Sicherheit, eine Schere mit 68% und einen Laptop mit 59% erkennen. Du siehst die Begrenzungsrahmen um die Objekte mit ihren Namen und der Erkennungssicherheit oben links annotiert:

In den nächsten Abschnitten lernst du, wie du den Webserver auf dem ESP32-CAM programmierst und wie du das YOLO-Erkennungssystem auf einem PC einrichtest.
Das ESP32-CAM Entwicklungsboard
Das ESP32-CAM Entwicklungsboard ist ein kompaktes Modul, das einen ESP32-S Chip, eine Kamera, einen eingebauten Blitz und einen microSD-Kartensteckplatz kombiniert. Das Board verfügt über integriertes Wi-Fi und Bluetooth und unterstützt eine OV2640 oder OV7670 Kamera mit bis zu 2 Megapixel Auflösung.

Im Tutorial beziehen wir uns auf das originale AI-Thinker model ESP32-CAM Board, aber es gibt viele Klone mit genau denselben Spezifikationen. Sie werden auf die gleiche Weise programmiert und verwendet – einschließlich desjenigen, das wir unter den benötigten Teilen aufgeführt haben.
Anschluss des FTDI Programmers
Du kannst den ESP32-CAM über einen Programming Shield oder über einen FTDI Programmer programmieren. Letzteres ist einfacher zu verwenden und flexibler. Es wandelt USB-Signale in serielle Signale um und ermöglicht die Programmierung von Mikrocontrollern wie Arduino und ESP32 über die UART-Schnittstelle. Das folgende Bild zeigt, wie du den FTDI Programmer mit dem ESP32-CAM Modul verbindest.

Die Verbindungen sind einfach. Beginne damit, GND des Programmers mit GND des ESP32-CAM Moduls zu verbinden (blaues Kabel). Dann verbinde die 5V Stromversorgung (rotes Kabel). Beachte, dass einige FTDI Programmer Jumper oder Schalter haben, um zwischen 3,3V und 5V zu wechseln. Achte darauf und verwende wenn möglich 5V.
Als nächstes verbinden wir den U0T (U0TXD) Pin des ESP32-CAM mit dem RXD Pin des Programmers (gelbes Kabel). Ebenso wird U0R mit TXD verbunden (grünes Kabel). Damit ist die serielle Kommunikation hergestellt.
Um den ESP32-CAM in den Programmiermodus zu versetzen, muss der IO0 Pin mit Masse (GND) verbunden werden. Möchtest du das Programm ausführen, darf der IO0 Pin nicht verbunden sein. Ich habe daher einen Schalter zwischen IO0 und GND (lila Kabel) eingebaut, mit dem ich zwischen Programmier- und Ausführmodus wechseln kann. Das Foto unten zeigt meine Verdrahtung des ESP32-CAM mit dem Schalter und dem FTDI Programmer:

Installation des ESP32 Cores
Wenn dies dein erstes Projekt mit einem Board der ESP32-Serie ist, musst du zuerst die Board-Installation durchführen. Sind ESP32 Boards bereits in deiner Arduino IDE installiert, kannst du diesen Abschnitt überspringen.
Öffne zunächst den Einstellungen-Dialog über „Preferences…“ im „Datei“-Menü. Es öffnet sich der unten gezeigte Einstellungen-Dialog.
Unter dem Reiter Einstellungen findest du unten ein Eingabefeld mit der Bezeichnung „Additional Board-Manager URLs“:

In dieses Eingabefeld kopiere die folgende URL: „https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json„
Damit weiß die Arduino IDE, wo sie die ESP32 Core Bibliotheken findet. Als nächstes installieren wir die ESP32 Core Bibliotheken über den Board-Manager.
Öffne den Board-Manager über „Tools-> Board -> Board-Manager“. Der Board-Manager erscheint in der linken Seitenleiste. Gib „ESP32“ in das Suchfeld oben ein und du solltest zwei Arten von ESP32 Boards sehen; die „Arduino ESP32 Boards“ und die „esp32 von Espressif“ Boards. Wir wollen die esp32 Bibliotheken von Espressif. Klicke auf den INSTALL Button und warte, bis der Download und die Installation abgeschlossen sind.

Auswahl des ESP32-CAM Boards
Klicke auf das Dropdown-Menü und dann auf „Select other Board and Port auswählen…“:

Es öffnet sich ein Dialog, in dem du „ESP32-CAM“ in die Suchleiste eingibst. Du siehst das Board „AI Thinker ESP32-CAM“ unter Boards. Klicke darauf, wähle den COM-Port aus, um es zu aktivieren, und klicke dann auf OK:

Wenn du trotz angeschlossenem ESP32-CAM über den FTDI Programmer keinen PORT auswählen kannst, fehlt der CP210X Treiber. Gehe zu SILICON LABS Software Downloads und lade den CP210x Treiber für dein Betriebssystem herunter, z.B. für Windows „CP210x VCP Windows“:

Dies lädt eine ZIP-Datei herunter. Entpacke sie und führe den Installer aus. Danach sollte dein ESP32-CAM als verbunden an einem USB-Port erscheinen. Falls weiterhin Probleme auftreten, musst du eventuell auch einen FTDI Driver installieren.
Installation der ESP32-CAM Bibliothek
Für unseren Webserver verwenden wir die esp32cam library. Gehe zum github repo, klicke auf den grünen CODE-Button und dann auf „Download ZIP“, um die Bibliothek herunterzuladen:

Klicke dann auf „Sketch -> Include Library -> Add .ZIP Library“:

und wähle den Pfad zur gerade heruntergeladenen ZIP-Datei aus, um die Bibliothek zu installieren. Im nächsten Abschnitt schreiben und erklären wir den Code für den Webserver auf dem ESP32-CAM.
Code für ESP32-CAM Webserver
Der folgende Code richtet ein ESP32-CAM Modul ein, um Bilder über ein Wi-Fi Netzwerk zu senden. Es nimmt Bilder auf und stellt sie als JPEG-Dateien für anfragende Clients bereit. Der Server läuft auf Port 80, dem Standard-HTTP-Port.
// www.makerguides.com
#include "WebServer.h"
#include "WiFi.h"
#include "esp32cam.h"
const char* WIFI_SSID = "SSID";
const char* WIFI_PASS = "PASSWORD";
const char* URL = "/cam.jpg";
static auto RES = esp32cam::Resolution::find(800, 600);
WebServer server(80);
void serveJpg() {
auto frame = esp32cam::capture();
if (frame == nullptr) {
Serial.println("CAPTURE FAILED!");
server.send(503, "", "");
return;
}
Serial.printf("CAPTURE OK %dx%d %db\n",
frame->getWidth(), frame->getHeight(),
static_cast<int>(frame->size()));
server.setContentLength(frame->size());
server.send(200, "image/jpeg");
WiFiClient client = server.client();
frame->writeTo(client);
}
void handleJpg() {
if (!esp32cam::Camera.changeResolution(RES)) {
Serial.println("CAN'T SET RESOLUTION!");
}
serveJpg();
}
void initCamera() {
{
using namespace esp32cam;
Config cfg;
cfg.setPins(pins::AiThinker);
cfg.setResolution(RES);
cfg.setBufferCount(2);
cfg.setJpeg(80);
bool ok = Camera.begin(cfg);
Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");
}
}
void initWifi() {
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED)
;
Serial.printf("http://%s%s\n",
WiFi.localIP().toString().c_str(), URL);
}
void initServer() {
server.on(URL, handleJpg);
server.begin();
}
void setup() {
Serial.begin(115200);
initWifi();
initCamera();
initServer();
}
void loop() {
server.handleClient();
}
Lass uns den Code in seine Komponenten aufteilen, um zu verstehen, wie er funktioniert.
Bibliotheken und Konstanten
Am Anfang des Codes binden wir die notwendigen Bibliotheken für den Webserver, die Wi-Fi-Funktionalität und die Kamerasteuerung ein.
#include "WebServer.h" #include "WiFi.h" #include "esp32cam.h"
Wir definieren außerdem Konstanten für die Wi-Fi-Zugangsdaten und den URL-Endpunkt zum Zugriff auf das Kamerabild.
const char* WIFI_SSID = "SSID"; const char* WIFI_PASS = "PASSWORD"; const char* URL = "/cam.jpg";
Natürlich musst du die Zugangsdaten durch die SSID und das Passwort deines Wi-Fi Netzwerks ersetzen.
Kameraauflösung
Wir setzen die gewünschte Auflösung für die Kamera. In diesem Fall wählen wir 800×600 Pixel.
static auto RES = esp32cam::Resolution::find(800, 600);
Initialisierung des Webservers
Als nächstes erstellen wir eine Instanz des Webservers, der auf Port 80 lauscht.
WebServer server(80);
Serve JPEG Funktion
Die serveJpg() Funktion nimmt ein Bild von der Kamera auf und sendet es als JPEG-Datei an den Client. Wenn die Aufnahme fehlschlägt, wird eine „503 Service Unavailable“ Antwort gesendet.
void serveJpg() {
auto frame = esp32cam::capture();
if (frame == nullptr) {
Serial.println("CAPTURE FAILED!");
server.send(503, "", "");
return;
}
Serial.printf("CAPTURE OK %dx%d %db\n",
frame->getWidth(), frame->getHeight(),
static_cast<int>(frame->size()));
server.setContentLength(frame->size());
server.send(200, "image/jpeg");
WiFiClient client = server.client();
frame->writeTo(client);
}
Hier versuchen wir zuerst, einen Frame aufzunehmen. Wenn das gelingt, protokollieren wir die Abmessungen und die Größe des Bildes, setzen die Inhaltslänge und senden das Bild an den Client zurück.
Handle JPEG Funktion
Die handleJpg() Funktion ändert die Kameraauflösung und ruft serveJpg() auf, um das Bild zu servieren.
void handleJpg() {
if (!esp32cam::Camera.changeResolution(RES)) {
Serial.println("CAN'T SET RESOLUTION!");
}
serveJpg();
}
Diese Funktion stellt sicher, dass die Kamera auf die gewünschte Auflösung eingestellt ist, bevor das Bild gesendet wird.
Kamerainitialisierung
Die initCamera() Funktion konfiguriert die Kameraeinstellungen, einschließlich Pinbelegung, Auflösung, Pufferanzahl und JPEG-Qualität.
void initCamera() {
{
using namespace esp32cam;
Config cfg;
cfg.setPins(pins::AiThinker);
cfg.setResolution(RES);
cfg.setBufferCount(2);
cfg.setJpeg(80);
bool ok = Camera.begin(cfg);
Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");
}
}
Wir erstellen ein Konfigurationsobjekt, setzen die notwendigen Parameter und initialisieren die Kamera. Eine Meldung wird im seriellen Monitor ausgegeben, die angibt, ob die Kamerainitialisierung erfolgreich war.
Wi-Fi Initialisierung
Die initWifi() Funktion verbindet den ESP32 mit dem angegebenen Wi-Fi Netzwerk.
void initWifi() {
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED)
;
Serial.printf("http://%s%s\n",
WiFi.localIP().toString().c_str(), URL);
}
Wir deaktivieren persistente Wi-Fi Verbindungen, setzen den Modus auf Station und versuchen, eine Verbindung zum Wi-Fi Netzwerk herzustellen. Nach erfolgreicher Verbindung geben wir die URL zum Zugriff auf das Kamerabild aus.
Server-Initialisierung
Die initServer() Funktion richtet den Server ein, um Anfragen für das Kamerabild zu bearbeiten.
void initServer() {
server.on(URL, handleJpg);
server.begin();
}
Wir definieren den URL-Endpunkt und verknüpfen ihn mit der handleJpg() Funktion, dann starten wir den Server.
Setup-Funktion
Die setup() Funktion initialisiert die serielle Kommunikation, Wi-Fi, Kamera und den Server.
void setup() {
Serial.begin(115200);
initWifi();
initCamera();
initServer();
}
Loop-Funktion
Schließlich bearbeitet die loop() Funktion kontinuierlich eingehende Client-Anfragen.
void loop() {
server.handleClient();
}
Diese Funktion stellt sicher, dass der Server auf Client-Anfragen reagiert und Clients die von der Kamera aufgenommenen Bilder abrufen können.
Test des ESP32-CAM Webservers
Lass uns nun den Webserver testen. Kompiliere und lade den obigen Code hoch. Um Code auf den ESP32-CAM hochzuladen, versetze das Board in den Programmiermodus, indem du den Schalter umlegst, drücke kurz den Reset-Knopf auf dem Board und klicke dann im Arduino IDE auf den Upload-Button.
Wenn du mehr Hilfe beim Hochladen des Codes auf den ESP32-CAM brauchst, schau dir das Programming the ESP32-CAM Tutorial an, das detailliertere Informationen bietet.
Nach einem erfolgreichen Upload wird die URL für die Kamerabilder im seriellen Monitor angezeigt und du solltest auch den Text „CAMERA OK“ sehen:
http://192.168.1.146/cam.jpg CAMERA OK
Kopiere diese URL in die Adressleiste deines Webbrowsers und du solltest das Bild sehen, das die Kamera aufgenommen hat:

Jedes Mal, wenn du im Webbrowser auf den Aktualisieren-Button klickst, nimmt der Webserver diese Anfrage entgegen, fordert den ESP32-CAM auf, ein neues Bild aufzunehmen, und sendet dieses neue Bild an deinen Webbrowser. Unten ein Bild meines Schreibtischs, das auf diese Weise aufgenommen wurde:

Im nächsten Abschnitt senden wir die Bilder an das YOLO Objekterkennungsmodell, um die Objekte in der Szene zu erkennen.
YOLO Objekterkennung
YOLO (You Only Look Once) ist ein Deep-Learning-Modell zur Objekterkennung, bekannt für seine Geschwindigkeit und Genauigkeit. Es wurde erstmals von Joseph Redmon et al. in 2016 vorgestellt. Seitdem gibt es viele verbesserte Versionen, wobei YOLO11 by Ultralytics die aktuellste (Stand Februar 2025) ist.
Wir verwenden jedoch ein älteres Modell YOLOv3v, da es kleiner und einfacher zu nutzen ist, aber nicht ganz so genau wie die neueren Modelle.

Das YOLO Modell ist ein tiefes konvolutionales Netzwerk, das ein RGB-Bild mit den Dimensionen 448x448x3 als Eingabe erhält und die Begrenzungsrahmen sowie Konfidenzwerte der erkannten Objekte in einem 7×7×30 Tensor ausgibt. Wir verwenden eine Version des Modells, die darauf trainiert ist, 80 different objects zu erkennen, wie zum Beispiel:
- Person
- Fahrrad
- Auto
- Motorrad
- …
- Schere
- Teddybär
- Haartrockner
- Zahnbürste
Wir gehen hier nicht ins Detail des Modells, aber wenn du mehr lernen möchtest, findest du hier Links zur Originalpublikation von YOLO, einer Beschreibung der Verbesserungen in Version 3 von YOLO und einem Anwendungsartikel mit nützlichen Informationen:
- YOLOv3: An Incremental Improvement
- You Only Look Once: Unified, Real-Time Object Detection
- YOLO v3: Visual and Real-Time Object Detection Model for Smart Surveillance Systems(3s)
Projektordnerstruktur
Um das YOLO Objekterkennungssystem auf einem PC auszuführen, müssen wir einen Projektordner erstellen, z.B. „esp32-cam-yolo-object-detection“. Innerhalb dieses Ordners erstellst du einen Unterordner namens „YOLO“ und eine Python-Datei namens „detect.py“. Deine Ordnerstruktur sollte wie folgt aussehen:

YOLO Dateien herunterladen
Als nächstes musst du die benötigten YOLO Dateien (Gewichte, Architektur-Konfiguration, Klassennamen) herunterladen und im „YOLO“ Ordner des Projekts ablegen. Hier sind die Links zu diesen Dateien:
- https://pjreddie.com/media/files/yolov3.weights
- https://github.com/pjreddie/darknet/blob/master/cfg/yolov3.cfg
- https://github.com/pjreddie/darknet/blob/master/data/coco.names
Der Inhalt deines „YOLO“ Ordners sollte dann so aussehen:

Virtuelle Umgebung erstellen
Wir müssen auch einige Python-Bibliotheken installieren, die wir in einer virtuellen Umgebung mit venv installieren. Öffne eine Kommandozeile und führe folgende Befehle aus:
cd esp32-cam-object-detection python -m venv venv venv\Scripts\activate.bat pip install opencv-python opencv-python-headless numpy torch torchvision
Der cd Befehl wechselt in den Projektordner. Der venv Befehl erstellt die virtuelle Umgebung und darin installieren wir die benötigten Bibliotheken mit pip install. Dadurch wird ein „venv“ Ordner im Projektordner erstellt, der die Bibliotheken enthält:

Objekterkennungscode
Zum Schluss kopiere den folgenden Code in die detect.py Datei in deinem Projektordner.
import cv2
import numpy as np
import urllib.request
# Camera URL
url = "http://192.168.1.146/cam.jpg"
# YOLO model files
weights_path = r"./YOLO/yolov3.weights"
config_path = r"./YOLO/yolov3.cfg"
names_path = r"./YOLO/coco.names"
# Load the YOLO model and COCO class names
net = cv2.dnn.readNet(weights_path, config_path)
with open(names_path, "r") as f:
classes = [line.strip() for line in f.readlines()]
layer_names = net.getLayerNames()
# Handling the return value of getUnconnectedOutLayers()
out_layers = net.getUnconnectedOutLayers()
if isinstance(out_layers[0], list):
output_layers = [layer_names[i[0] - 1] for i in out_layers]
else:
output_layers = [layer_names[i - 1] for i in out_layers]
# Generate random colors for each class
colors = np.random.uniform(0, 255, size=(len(classes), 3))
def detect_objects(frame):
height, width, _ = frame.shape
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
layer_outputs = net.forward(output_layers)
boxes = []
confidences = []
class_ids = []
for output in layer_outputs:
for detection in output:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.3:
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.3, 0.4)
# Draw detections on the frame
if len(indexes) > 0 and isinstance(indexes, np.ndarray):
indexes = indexes.flatten()
for i in indexes:
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
confidence = confidences[i]
color = colors[class_ids[i]]
print(f"Detected: {label} with confidence {confidence:.2f}")
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
cv2.putText(
frame,
f"{label} {confidence:.2f}",
(x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
color,
2,
)
return frame
def main():
cv2.namedWindow("Object Detection", cv2.WINDOW_AUTOSIZE)
while True:
try:
img_resp = urllib.request.urlopen(url)
imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8)
frame = cv2.imdecode(imgnp, -1)
frame = detect_objects(frame)
cv2.imshow("Object Detection", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
except Exception as e:
print(f"Error occurred: {e}")
break
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
Der obige Code implementiert ein Objekterkennungssystem mit dem YOLO Modell und OpenCV. Er nimmt Bilder von einem Kamerafeed auf und erkennt Objekte in Echtzeit, wobei die Ergebnisse auf dem Bildschirm angezeigt werden.
Bibliotheken importieren
Wir beginnen mit dem Import der notwendigen Bibliotheken: cv2 für Computer-Vision-Aufgaben, numpy für numerische Operationen und urllib.request für das Handling von URL-Anfragen.
import cv2 import numpy as np import urllib.request
Kamera-URL
Hier definieren wir die URL des Kamerafeeds, von dem wir Bilder aufnehmen. Du musst diese Konstante durch die URL ersetzen, die dein Webserver liefert:
url = "http://192.168.1.146/cam.jpg"
YOLO Modell-Dateien
Als nächstes geben wir die Pfade zu den YOLO Modell-Dateien an: die Gewichtsdatei, die Konfigurationsdatei und die Namen der Objekte, die das Modell erkennen kann.
weights_path = r"./YOLO/yolov3.weights" config_path = r"./YOLO/yolov3.cfg" names_path = r"./YOLO/coco.names"
YOLO Modell laden
Wir laden das YOLO Modell mit OpenCVs dnn Modul und lesen die Klassennamen aus der angegebenen Datei. Die Layer-Namen werden ebenfalls für die spätere Verwendung abgerufen.
net = cv2.dnn.readNet(weights_path, config_path)
with open(names_path, "r") as f:
classes = [line.strip() for line in f.readlines()]
layer_names = net.getLayerNames()
Ausgabe-Layer
Wir bestimmen die Ausgabelayer des Netzwerks. Das ist wichtig, um zu wissen, welche Layer die finalen Erkennungen liefern.
out_layers = net.getUnconnectedOutLayers()
if isinstance(out_layers[0], list):
output_layers = [layer_names[i[0] - 1] for i in out_layers]
else:
output_layers = [layer_names[i - 1] for i in out_layers]
Farben für Klassen generieren
Um die erkannten Objekte zu visualisieren und zu unterscheiden, generieren wir zufällige Farben für die Begrenzungsrahmen.
colors = np.random.uniform(0, 255, size=(len(classes), 3))
Objekterkennungsfunktion
Die detect_objects() Funktion nimmt einen Bild-Frame als Eingabe, verarbeitet ihn und erkennt Objekte mit dem YOLO Modell. Sie gibt den Frame mit gezeichneten Begrenzungsrahmen und Labels zurück.
def detect_objects(frame):
height, width, _ = frame.shape
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
layer_outputs = net.forward(output_layers)
boxes = []
confidences = []
class_ids = []
In dieser Funktion erstellen wir zuerst einen Blob aus dem Eingabeframe, eine vorverarbeitete Version des Bildes, die für das Modell geeignet ist. Dann führen wir einen Forward-Pass durch, um die Ausgabe des Modells zu erhalten.
Verarbeitung der Erkennungen
Wir durchlaufen die Ausgaben, um Begrenzungsrahmen, Konfidenzwerte und Klassen-IDs der erkannten Objekte zu extrahieren. Nur Erkennungen mit einer Konfidenz größer als 0,3 werden als gültig betrachtet. Du kannst diesen Wert (0…1) anpassen, um weniger oder mehr sichere Erkennungen anzuzeigen.
for output in layer_outputs:
for detection in output:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.3:
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
Non-Maximum Suppression
Um überlappende, redundante Rahmen zu eliminieren, wenden wir Non-Maximum Suppressio (NMS) an, um nur die besten Begrenzungsrahmen zu behalten.
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.3, 0.4)
Zeichnen der Erkennungen
Wir zeichnen die Begrenzungsrahmen und Labels für jedes erkannte Objekt auf den Frame. Der erkannte Klassen-/Objektname und der Konfidenzwert werden angezeigt.
if len(indexes) > 0 and isinstance(indexes, np.ndarray):
indexes = indexes.flatten()
for i in indexes:
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
confidence = confidences[i]
color = colors[class_ids[i]]
print(f"Detected: {label} with confidence {confidence:.2f}")
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
cv2.putText(
frame,
f"{label} {confidence:.2f}",
(x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX,
0.5,
color,
2,
)
Hauptfunktion
Die main() Funktion richtet ein Fenster zur Anzeige der Erkennungen ein und nimmt kontinuierlich Frames vom Kamerafeed auf. Sie verarbeitet jeden Frame mit der detect_objects() Funktion und zeigt das Ergebnis an.
def main():
cv2.namedWindow("Object Detection", cv2.WINDOW_AUTOSIZE)
while True:
try:
img_resp = urllib.request.urlopen(url)
imgnp = np.array(bytearray(img_resp.read()), dtype=np.uint8)
frame = cv2.imdecode(imgnp, -1)
frame = detect_objects(frame)
cv2.imshow("Object Detection", frame)
if cv2.waitKey(1) & 0xFF == ord("q"):
break
except Exception as e:
print(f"Error occurred: {e}")
break
cv2.destroyAllWindows()
Es öffnet sich ein Fenster, und wenn du „q“ drückst, während das Fenster im Vordergrund ist, wird die Anwendung beendet.
Ausführungseintrittspunkt
Zum Schluss prüfen wir, ob das Skript direkt ausgeführt wird, und rufen die main() Funktion auf, um das Programm zu starten.
if __name__ == "__main__":
main()
Im nächsten Abschnitt fassen wir alles zusammen und starten unser Objekterkennungssystem.
Objekterkennung starten
Starte zuerst dein ESP32-CAM Modul mit dem Webserver-Code und stelle sicher, dass der ESP32-CAM Bilder aufnimmt und diese im Webbrowser unter der im seriellen Monitor angezeigten URL anzeigt. Achte auch darauf, dass diese URL in detect.py verwendet wird, z.B. in meinem Fall ist diese URL:
url = "http://192.168.1.146/cam.jpg"
Als nächstes startest du den YOLO Objektdetektor. Wechsle in deinen Projektordner („esp32-cam-object-detection“), aktiviere die virtuelle Umgebung und führe den Detektor-Code detect.py aus:
cd esp32-cam-object-detection venv\Scripts\activate.bat python detect.py
Beachte, dass du die virtuelle Umgebung mit folgendem Befehl deaktivieren kannst:
venv\Scripts\deactivate.bat
Wenn der Code läuft, solltest du die Namen der erkannten Objekte mit den Konfidenzwerten in der Konsole sehen:
Detected: cup with confidence 0.76 Detected: laptop with confidence 0.39 Detected: cup with confidence 0.51 Detected: laptop with confidence 0.33 Detected: cup with confidence 0.44 Detected: cup with confidence 0.65 Detected: cup with confidence 0.63
Außerdem öffnet sich ein Fenster namens „Object Detection“, das das aktuelle Bild der Kamera mit Begrenzungsrahmen um die erkannten Objekte zeigt. Unten ein Beispiel, bei dem das System korrekt eine Tasse, eine Fernbedienung und einen Laptop erkennt:

Wenn du mehr Beispiele für die Erkennungsfähigkeiten des YOLO Modells sehen möchtest, besuche die folgende YOLO Demo Video.
Fazit
In diesem Tutorial hast du gelernt, wie man ein Objekterkennungssystem baut. Das ESP32-CAM Modul wurde verwendet, um Bilder aufzunehmen und einen Webserver für diese Bilder zu betreiben. Die Bilder wurden dann per Wi-Fi an einen PC gesendet, der eine Objekterkennungssoftware basierend auf dem YOLO Deep-Learning-Modell ausführt.
Das Kompilieren und Hochladen von Code auf den ESP32-CAM kann recht knifflig sein. Wenn du auf Probleme stößt, schau dir das Programming the ESP32-CAM Tutorial an, das detailliertere Anleitungen bietet.
Beachte, dass unser kleines Objekterkennungssystem auf 80 vordefinierte Objekte (oder Klassen) beschränkt ist. Du kannst das YOLO Modell jedoch mit eigenen Objekten trainieren. Das How to Train YOLOv3 to Detect Custom Objects? Tutorial könnte dir dabei helfen, wenn du das tun möchtest.
Wenn du weitere Fragen hast, kannst du sie gerne im Kommentarbereich stellen.
Viel Spaß beim Tüfteln ; )


