Skip to content

Technik Blog

Programmieren | Arduino | ESP32 | MicroPython | Python | Raspberry Pi | Raspberry Pi Pico

Menu
  • Smarthome
  • Arduino
  • ESP32 & Co.
  • Raspberry Pi & Pico
  • Solo Mining
  • Über mich
  • Deutsch
  • English
Menu

ESP32-CAM – Bewegung ermitteln mit Python3

Posted on 18. April 202210. März 2024 by Stefan Draeger

Wie man eine Bewegung an einer ESP32-CAM mithilfe von Python3 erkennt, möchte ich dir gerne in diesem Beitrag zeigen.

Bewegung mit Python3 an einer ESP32-CAM erkennen
Bewegung mit Python3 an einer ESP32-CAM erkennen

Wie man mit Python ein Bild von einer ESP32-CAM auf dem Computer speichert, habe ich dir bereits im Beitrag Python – ESP32 CAM Bild speichern gezeigt.

Die ESP32-CAM habe ich dir bereits im Beitrag Einrichten der ESP32-CAM und erster betrieb gezeigt und die verfügbaren Kameralinsen im Beitrag ESP32 CAM – Vergleich der verfügbaren Kameralinsen vorgestellt.

  • Benötigte Ressourcen für dieses Projekt
  • Wie wird eine Bewegung erkannt?
    • Pixel vergleichen
    • Bilder vergleichen mit OpenCV
  • Programmieren
    • Schritt 1 – Bilder von der ESP32-CAM auf dem Computer speichern
      • Anpassen der Auflösung
    • Schritt 2 – Zeit x warten und ein weiteres Bild aufnehmen
    • Schritt 3 – Bilder vergleichen
    • Schritt 4 – Aktion bei gleichen Bildern
    • Schritt 5 – Aktion bei ungleichen Bildern
  • Download des Python Skriptes zum erkennen einer Bewegung an der ESP32-CAM

Benötigte Ressourcen für dieses Projekt

Wenn du dieses Projekt nachbauen möchtest, dann benötigst du:

  • eine ESP32-CAM*,
    • ein FTDI Modul* mit Breadboarkabel*, oder
    • ein ESP32-CAM-MB*

Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!

ESP32-CAM
ESP32-CAM
FTDI Module
FTDI Module
ESP32-CAM-MB
ESP32-CAM-MB

Die ESP32-CAM wird mit einer einfachen 66° Linse ausgeliefert, welche für den nachfolgenden Aufbau gut funktionieren würde, jedoch möchte ich einen größeren Winkel kontrollieren und verwende eine 120° Linse.

ESP32 CAM - Kameralinse 120° Grad Aufnahmewinkel
ESP32 CAM – Kameralinse 120° Grad Aufnahmewinkel
ESP32 CAM - Kameralinse 66° Grad Aufnahmewinkel
ESP32 CAM – Kameralinse 66° Grad Aufnahmewinkel

Zum Programmieren des Python3 Programmes verwende ich die Community Edition von PyCharm.

Wie wird eine Bewegung erkannt?

Im Grunde muss man nur zwei Bilder in einem Abstand von x Minuten / Sekunden aufnehmen und diese beiden Bilder miteinander vergleichen. Der Vergleich jeweils ist der entscheidende Part.

Pixel vergleichen

Am einfachsten (jedenfalls dachte ich es) ist es, die beiden Bilder Pixel für Pixel zu vergleichen.

Da die ESP32-CAM jedoch selbst bei gleich guten / schlechten Lichtverhältnissen manchmal unterschiedlich gute Bilder liefert, muss hier ein Offset in den RGB Wert des Pixels eingerechnet werden.

Selbst aber mit dem Offset am RGB Wert wurde dann nicht zuverlässig ein Unterschied erkannt und ich habe diese Idee wieder „eingestampft“.

Bilder vergleichen mit OpenCV

Das Modul OpenCV bietet Funktionen zum Vergleichen von Bildern. Das nachfolgende Programm habe ich von der Seite Image Difference with OpenCV and Python von pyimagesearch.com entnommen und für die Bedürfnisse an dieses Projekt angepasst.

Programmieren

Im Nachfolgenden wollen wir nun Schritt für Schritt das Programm aufbauen und Bilder von der ESP32-CAM vergleichen.

Schritt 1 – Bilder von der ESP32-CAM auf dem Computer speichern

Wie bereits erwähnt, habe ich dir bereits gezeigt, wie man ein Bild von der ESP32 CAM auf dem Computer speichern kann.

import requests
from PIL import Image
from io import BytesIO

url = 'http://192.168.178.33/capture'
output = 'data/output.jpg'

r = requests.get(url)
img = Image.open(BytesIO(r.content))
img.save(output)

Diese paar Zeilen lagern wir nun in eine Funktion aus und geben dann den Dateinamen des Bildes zurück.

outputFolder = 'data/';
outputFileExt = '.jpg';

def takePicture():
    r = requests.get(url)
    img = Image.open(BytesIO(r.content))
    timestamp = round(time.time());
    outputfilename = outputFolder + str(timestamp) + outputFileExt;
    img.save(outputfilename);
    return outputfilename;

Anpassen der Auflösung

Über das Webinterfache können wir einen Stream starten und auch Standbilder speichern, dabei wird die Auflösung über eine Dropdownliste eingestellt.

ESP32-CAM WebInterface verfügbare Auflösungen
ESP32-CAM Webinterface verfügbare Auflösungen

Die Bilder werden aber in unserem Programm zunächst im Defaultformat von 400×276 Pixel aufgenommen. Wenn wir eine andere Auflösung wollen, so müssen wir diese Einstellung über einen HTTP Request setzen.

import requests

"""
Index   | Auflösung
13      | 1600 x 1200
12      | 1280 x 1024
11      | 1280 x 720
10      | 1024 x 768
9       | 800 x 600
8       | 640 x 480
7       | 480 x 320
6       | 400 x 296
5       | 320 x 240
4       | 240 x 240
3       | 240 x 176
2       | 176 x 144
1       | 160 x 120
0       | 96 x 96
"""

espCamIpAdress = 'http://192.168.178.33';

def setResolution():
    url = espCamIpAdress + '/control?var=framesize&val=' + str(index);
    r = requests.get(url)
    if r.status_code > 200:
        print("Fehler", str(r.status_code), "bei setzen der Auflösung an der ESP32 CAM!")
    time.sleep(1)

Schritt 2 – Zeit x warten und ein weiteres Bild aufnehmen

Mit der Funktion „sleep“ aus dem Modul time können wir das Programm eine Zeit x Pausieren.

import time

time.sleep(0.5) //500 ms.
time.sleep(1) //1 Sekunde
time.sleep(60) //1 Minute
time.sleep(3600) //1 Stunde
time.sleep(86400) //1 Tag

Wenn wir also das nächste Bild in 5 Minuten aufnehmen möchten, müssen wir schreiben:

import time

time.sleep(60 * 5) //5 Minuten Pause, oder
time.sleep(300) //5 Minuten Pause

Nehmen wir nun 2 Bilder mit einem Abstand von 300 Sekunden bzw. 5 Minuten auf.

print("Take first image.")
first_image = takePicture()
print("Wait 300 seconds.")
time.sleep(300);
print("Take second image.")
second_image = takePicture()

Schritt 3 – Bilder vergleichen

Nun vergleichen wir diese beiden Bilder mit dem Modul OpenCV.

Die beiden Bilder werden dazu in Graustufen umgewandelt und erneut eingelesen.

image1 = cv2.cvtColor(cv2.imread(first_image), cv2.COLOR_BGR2GRAY)
image2 = cv2.cvtColor(cv2.imread(takePicture()), cv2.COLOR_BGR2GRAY)

(score, diff) = compare_ssim(image1, image2, full=True)
diff = (diff * 255).astype("uint8")
print("SSIM: {}".format(score))

Danach vergleichen wir diese mit der Funktion „compare_ssim“.

(score, diff) = compare_ssim(image1, image2, full=True)

Wenn du mehr über diese Funktion lesen möchtest dann empfehle ich dir die offizielle Seite https://scikit-image.org/docs/0.12.x/api/skimage.measure.html#skimage.measure.compare_ssim empfehlen.

Als Rückgabewert erhältst du zwei Werte in einem Tupel, zum einen den Score mit einem Gleitkommawert zwischen 0 und 1 und einen Wert „diff“ welcher in der verlinkten Dokumentation wie folgt beschrieben ist:

The gradient of the structural similarity index between X and Y [R262]. This is only returned if gradient is set to True.

Jedoch brauchen wir diesen in unserem Beispiel nicht! Da wir jedoch ein Tupel mit diesen beiden Werten von der Funktion zurückbekommen, müssen wir dieses initialisieren.

print("SSIM: {}".format(score))

Wir arbeiten nun mit dem Score weiter…

Schritt 4 – Aktion bei gleichen Bildern

Wenn die beiden Bilder gleich bzw. sehr identisch sind, wollen wir mit dem nächsten Zyklus des Programmes durchlaufen…

Schritt 5 – Aktion bei ungleichen Bildern

Nehmen wir an, dass ein Score kleiner als 0.8 für zwei ungleiche Bilder gilt. In diesem Fall wollen wir eine Aktion auslösen.

if score < 0.8:
   imageResolution = resolutions[13]
   setResolution()
   filename = takePicture()
   sendMail(filename)

In meinem Fall ändere ich die Auflösung auf das Maximum von 1600 x 1200 Pixel, mache ein Foto und versende dieses per E-Mail an mich selber. Wie man eine E-Mail aus einem Python3 Skript sendet, habe ich dir bereits im gleichnamigen Beitrag Senden einer E-Mail aus einem Python3 Skript ausführlich erläutert.

Natürlich könnten wir auch einen GPIO aktivieren und so eine Sirene, Lampe etc. steuern und somit darauf reagieren.

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from os.path import basename

def sendMail(filename):
    # Betreff & Inhalt
    subject = "Hallo Welt!"
    body = "Hier steht ein Text."
    # Message Objekt für die E-Mail
    # später kann an dieses Objekt eine
    # oder mehrere Dateien angehängt
    # werden.
    msg = MIMEMultipart()
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = reciever
    msg.attach(MIMEText(body, 'plain'))

    with open(filename, "rb") as file:
        part = MIMEApplication(
            file.read(),
            Name=basename(filename)
        )
        # After the file is closed
        part['Content-Disposition'] = 'attachment; filename="%s"' % basename(filename)
        msg.attach(part)

    # Erzeugen einer Mail Session
    smtpObj = smtplib.SMTP(smtpServer, smtpPort)
    # Debuginformationen auf der Konsole ausgeben
    smtpObj.set_debuglevel(1)
    # Wenn der Server eine Authentifizierung benötigt dann...
    smtpObj.starttls()
    smtpObj.login(username, password)
    # absenden der E-Mail
    smtpObj.sendmail(sender, reciever, msg.as_string())
    smtpObj.close()

In meinem Fall habe ich die Mail mit Anhang an meinen Account „info@draeger-it.blog“ von der Adresse „esp32_mailer@web.de“ gesendet.

Die Adresse „esp32_mailer@web.de“ habe ich mir eigens für diesen Beitrag angelegt.

Download des Python Skriptes zum erkennen einer Bewegung an der ESP32-CAM

Hier nun das komplette Skript um eine Bewegung an der ESP32-CAM mit Python3 zu erkennen und bei unterschiedlichen Bildern eine E-Mail zu senden.

ESP32-CAM Bewegung mit Python3 erkennenHerunterladen

2 thoughts on “ESP32-CAM – Bewegung ermitteln mit Python3”

  1. Nane sagt:
    12. Juli 2023 um 11:25 Uhr

    Hi Stefan!

    Das sieht sehr cool aus! Weißt du, ob es auch die Möglichkeit gibt, die Bildwerte im Stream auszulesen, ohne das Bild zu speichern?
    Ich arbeite mit der Arduino IDE und würde gerne LEDs steuern, jenachdem wie das Kamerabild aussieht.
    Zum Beispiel dachte ich an den mittleren Grauwert. Wenn er dunkler ist, werden die LEDs dunkler und umgekehrt.
    Das wäre super, wenn das in Echtzeit ginge, habe dazu aber noch nichts sinnvolles gefunden.

    LG
    Nane

    Antworten
    1. Stefan Draeger sagt:
      12. Juli 2023 um 14:17 Uhr

      Hi,

      wie das in Echtzeit geht weiß ich derzeit leider nicht, es gibt aber auch eine einfache VGA Kamera für den Arduino.
      Bei der könnte ich mir das gut vorstellen.

      Gruß, Stefan

      Antworten

Schreibe einen Kommentar Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Fragen oder Feedback?

Du hast eine Idee, brauchst Hilfe oder möchtest Feedback loswerden?
Support-Ticket erstellen

Newsletter abonnieren

Bleib auf dem Laufenden: Erhalte regelmäßig Updates zu neuen Projekten, Tutorials und Tipps rund um Arduino, ESP32 und mehr – direkt in dein Postfach.

Jetzt Newsletter abonnieren

Unterstütze meinen Blog

Wenn dir meine Inhalte gefallen, freue ich mich über deine Unterstützung auf Tipeee.
So hilfst du mit, den Blog am Leben zu halten und neue Beiträge zu ermöglichen.

draeger-it.blog auf Tipeee unterstützen

Vielen Dank für deinen Support!
– Stefan Draeger

Kategorien

Tools

  • Unix-Zeitstempel-Rechner
  • ASCII Tabelle
  • Spannung, Strom, Widerstand und Leistung berechnen
  • Widerstandsrechner
  • 8×8 LED Matrix Tool
  • 8×16 LED Matrix Modul von Keyestudio
  • 16×16 LED Matrix – Generator

Links

Blogverzeichnis Bloggerei.de TopBlogs.de das Original - Blogverzeichnis | Blog Top Liste Blogverzeichnis trusted-blogs.com

Stefan Draeger
Königsberger Str. 13
38364 Schöningen

Tel.: 01778501273
E-Mail: info@draeger-it.blog

Folge mir auf

  • Impressum
  • Datenschutzerklärung
  • Disclaimer
  • Cookie-Richtlinie (EU)
©2025 Technik Blog | Built using WordPress and Responsive Blogily theme by Superb
Cookie-Zustimmung verwalten
Wir verwenden Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wir tun dies, um das Surferlebnis zu verbessern und um personalisierte Werbung anzuzeigen. Wenn Sie diesen Technologien zustimmen, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn Sie Ihre Zustimmung nicht erteilen oder zurückziehen, können bestimmte Funktionen beeinträchtigt werden.
Funktional Immer aktiv
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Vorlieben
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Statistiken
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt. Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Marketing
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Optionen verwalten Dienste verwalten Verwalten von {vendor_count}-Lieferanten Lese mehr über diese Zwecke
Einstellungen anzeigen
{title} {title} {title}