ESP32-Cam & KI: Objekt Erfassung und Identifikation

Das mit dem ESP32-Cam Board, eine günstige Web-Cam erstellt werden kann, wurde hier bereits vorgestellt.
Diesmal möchte ich mal zeigen, wie ein Live-Stream der ESP32-Cam, Objekte erkennt und diese in der Bildausgabe direkt bezeichnet. Alles mit Hilfe von der KI YOLO (You Only Look Once).


Das kann nützlich sein, um zum Beispiel automatisiert herauszufinden, ob ein Auto, ein Hund oder eine Person, auf dem Videobild der Haustüre zu sehen ist.
Dieses Tutorial soll lediglich zeigen, wie man ohne großen Aufwand solche KI – Lösungen zum laufen bringt. Wer sich darüber hinaus intensiver mit diesem Thema beschäftigen möchte, dem möchte ich die Beiträge von Udo Würtz empfehlen.

Im Video zeige ich, wie man die Kamera zum Laufen bringt, wie man Python auf dem Computer einrichtet und wie die Kamera und der Computer miteinander sprechen können.
In diesem Artikel zeige ich die 5 Schritte wie es funktioniert.

Arduino IDE:
Im ersten Schritt wird auf dem ESP32-Cam ein kleiner Sketch aufgespielt, in dem lediglich der zu verwendene Accesspoint Namen und Passwort ergänzt werden muss. Benötigte Library ist bei dem Github User yoursunny zu finden. Aufgespielt wird wie hier schon mal vorgestellt.

Quellcode:

#include <WebServer.h>
#include <WiFi.h>
#include <esp32cam.h>
 
const char* WIFI_SSID = "AP-Name";
const char* WIFI_PASS = "Password";


 
WebServer server(80);
 
 
static auto loRes = esp32cam::Resolution::find(320, 240);
static auto midRes = esp32cam::Resolution::find(350, 530);
static auto hiRes = esp32cam::Resolution::find(800, 600);
void serveJpg()
{
  auto frame = esp32cam::capture();
  if (frame == nullptr) {
    Serial.println("CAPTURE FAIL");
    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 handleJpgLo()
{
  if (!esp32cam::Camera.changeResolution(loRes)) {
    Serial.println("SET-LO-RES FAIL");
  }
  serveJpg();
}
 
void handleJpgHi()
{
  if (!esp32cam::Camera.changeResolution(hiRes)) {
    Serial.println("SET-HI-RES FAIL");
  }
  serveJpg();
}
 
void handleJpgMid()
{
  if (!esp32cam::Camera.changeResolution(midRes)) {
    Serial.println("SET-MID-RES FAIL");
  }
  serveJpg();
}
 
 
void  setup(){
  Serial.begin(115200);
  Serial.println();
  {
    using namespace esp32cam;
    Config cfg;
    cfg.setPins(pins::AiThinker);
    cfg.setResolution(hiRes);
    cfg.setBufferCount(2);
    cfg.setJpeg(80);
 
    bool ok = Camera.begin(cfg);
    Serial.println(ok ? "CAMERA OK" : "CAMERA FAIL");
  }
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  Serial.print("http://");
  Serial.println(WiFi.localIP());
  Serial.println("  /cam-lo.jpg");
  Serial.println("  /cam-hi.jpg");
  Serial.println("  /cam-mid.jpg");
 
  server.on("/cam-lo.jpg", handleJpgLo);
  server.on("/cam-hi.jpg", handleJpgHi);
  server.on("/cam-mid.jpg", handleJpgMid);
 
  server.begin();
}
 
void loop()
{
  server.handleClient();
}

Nach dem Aufspielen des Sketches auf den ESP32-Cam sollte man im Seriellen Monitor prüfen ob die Kamera erkannt wurde und ob das Board eine IP-Adresse erhalten hat.

Die lokale Web-Seite gibt auch schon ein Stream im Browser aus, bei
http://erhalteneIP-Adresse/cam-hi.jpg
und ist somit vorbereitet auf die Python Übergabe.

Python bereitstellen:
Jetzt wird Python benötigt. Sofern noch nicht installiert, kann bei https://www.python.org/downloads/ für das entsprechende Betriebssystem geladen und installiert werden. Bitte dann wie im Video zu sehen einmal testen.

Python-Bibliotheken:
Nun noch die benötigten Python-Bibliotheken mit pip installieren. (ggf auch pip upgraden)
pip install cvlib (Erkennung und Verarbeitung von Bildern)
pip install numpy (Effiziente mathematische und statistische Operationen in Python durchzuführen)
pip install opencv-python (Gesichtserkennung, Objekterkennung, Gestenerkennung)
pip install matplotlib (Daten analysieren und visualisieren)
pip install tensorflow
(Maschinelles Lernen und künstliche Intelligenz)

Erstelle nun eine Python-Datei mit diesem Inhalt, passe die 9. Zeile mit deiner lokalen IP-Adresse an und speichere die als main.py:

import cv2
import matplotlib.pyplot as plt
import cvlib as cv
import urllib.request
import numpy as np
from cvlib.object_detection import draw_bbox
import concurrent.futures
 
url='http://10.10.20.81/cam-hi.jpg'
im=None
 
def run1():
    cv2.namedWindow("live transmission", cv2.WINDOW_AUTOSIZE)
    while True:
        img_resp=urllib.request.urlopen(url)
        imgnp=np.array(bytearray(img_resp.read()),dtype=np.uint8)
        im = cv2.imdecode(imgnp,-1)
 
        cv2.imshow('live transmission',im)
        key=cv2.waitKey(5)
        if key==ord('q'):
            break
            
    cv2.destroyAllWindows()
        
def run2():
    cv2.namedWindow("detection", cv2.WINDOW_AUTOSIZE)
    while True:
        img_resp=urllib.request.urlopen(url)
        imgnp=np.array(bytearray(img_resp.read()),dtype=np.uint8)
        im = cv2.imdecode(imgnp,-1)
 
        bbox, label, conf = cv.detect_common_objects(im)
        im = draw_bbox(im, bbox, label, conf)
 
        cv2.imshow('detection',im)
        key=cv2.waitKey(5)
        if key==ord('q'):
            break
            
    cv2.destroyAllWindows()
 
 
 
if __name__ == '__main__':
    print("started")
    with concurrent.futures.ProcessPoolExecutor() as executer:
            f1= executer.submit(run1)
            f2= executer.submit(run2)

Finaler Test:
Jetzt sollte die main.py in der Eingabeaufforderung gestartet werden können.
Es erscheinen zwei Fenster:
Einmal der eigentliche Live-Stream des ESP32-Cam und im zweiten werden nun erkannte Objekte eingerahmt und bezeichnet.


Hardware:
ESP32-CAM mit Erweiterungsmodul


Video:


Ein 3D-Druck Gehäuse (3Teilig) mit Standfuß für den ESP32-Cam, habe ich mit TinkerCad erstellt und bei Thingiverse abgelegt.

,