In diesem Beitrag zeige ich dir, wie du mit Python, OpenCV und MediaPipe eine einfache Echtzeit-Gestenerkennung per Webcam umsetzen kannst. Der Code erkennt sechs Handgesten – von „Daumen hoch“ bis „OK“ – und zeigt sie live im Video-Feed an. Ich erkläre dir die Installation, den Code, Einsatzszenarien und Verbesserungsmöglichkeiten. Spoiler: Das Verfahren ist relativ ungenau, aber ein toller Einstieg in die Welt der Computer Vision!


Installation

Bevor du loslegst, stelle sicher, dass du die nötigen Bibliotheken installierst. Du brauchst Python 3.6+ und eine funktionierende Webcam. Öffne dein Terminal und führe folgende Befehle aus:

bash

pip install opencv-python
pip install mediapipe
pip install numpy
  • opencv-python: Für die Videoaufnahme und Bildverarbeitung.
  • mediapipe: Googles Framework für maschinelles Lernen, hier für Handerkennung.
  • numpy: Für numerische Berechnungen wie Abstände.

Teste nach der Installation, ob deine Webcam funktioniert, z. B. mit einem einfachen OpenCV-Skript.


Der Code

Hier ist der vollständige Code für die Gestenerkennung:

python

import cv2
import mediapipe as mp
import numpy as np

# Initialisieren von MediaPipe
mp_drawing = mp.solutions.drawing_utils
mp_hands = mp.solutions.hands

# Laden des MediaPipe-Modells
hands = mp_hands.Hands(static_image_mode=False, max_num_hands=2, min_detection_confidence=0.7, min_tracking_confidence=0.5)

# Starten der Videoaufnahme
cap = cv2.VideoCapture(0)

# Webcam-Check
if not cap.isOpened():
    print("Fehler: Webcam konnte nicht geöffnet werden.")
    exit()

gestures = ["Daumen hoch", "Daumen runter", "Faust", "Zeigefinger", "Stinkefinger", "OK"]
threshold = 0.1  # Schwellenwert für Gestenerkennung

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        print("Fehler: Kein Frame von der Webcam empfangen.")
        break

    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = hands.process(frame_rgb)

    gesture_detected = None

    if results.multi_hand_landmarks:
        for landmarks in results.multi_hand_landmarks:
            mp_drawing.draw_landmarks(frame, landmarks, mp_hands.HAND_CONNECTIONS)

            thumb_tip = landmarks.landmark[4]
            index_tip = landmarks.landmark[8]
            middle_tip = landmarks.landmark[12]
            ring_tip = landmarks.landmark[16]
            pinky_tip = landmarks.landmark[20]
            wrist = landmarks.landmark[0]
            thumb_mcp = landmarks.landmark[2]
            index_mcp = landmarks.landmark[5]
            middle_mcp = landmarks.landmark[9]
            ring_mcp = landmarks.landmark[13]
            pinky_mcp = landmarks.landmark[17]

            cv2.putText(frame, "Daumen", (int(thumb_tip.x * frame.shape[1]), int(thumb_tip.y * frame.shape[0])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
            cv2.putText(frame, "Zeigefinger", (int(index_tip.x * frame.shape[1]), int(index_tip.y * frame.shape[0])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
            cv2.putText(frame, "Mittelfinger", (int(middle_tip.x * frame.shape[1]), int(middle_tip.y * frame.shape[0])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
            cv2.putText(frame, "Ringfinger", (int(ring_tip.x * frame.shape[1]), int(ring_tip.y * frame.shape[0])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)
            cv2.putText(frame, "Kleiner Finger", (int(pinky_tip.x * frame.shape[1]), int(pinky_tip.y * frame.shape[0])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2)

            thumb_wrist_distance = cv2.norm((thumb_tip.x, thumb_tip.y), (wrist.x, wrist.y))
            index_wrist_distance = cv2.norm((index_tip.x, index_tip.y), (wrist.x, wrist.y))
            middle_wrist_distance = cv2.norm((middle_tip.x, middle_tip.y), (wrist.x, wrist.y))
            ring_wrist_distance = cv2.norm((ring_tip.x, ring_tip.y), (wrist.x, wrist.y))
            pinky_wrist_distance = cv2.norm((pinky_tip.x, pinky_tip.y), (wrist.x, wrist.y))

            thumb_folded = cv2.norm((thumb_tip.x, thumb_tip.y), (thumb_mcp.x, thumb_mcp.y))
            index_folded = cv2.norm((index_tip.x, index_tip.y), (index_mcp.x, index_mcp.y))
            middle_folded = cv2.norm((middle_tip.x, middle_tip.y), (middle_mcp.x, middle_mcp.y))
            ring_folded = cv2.norm((ring_tip.x, ring_tip.y), (ring_mcp.x, ring_mcp.y))
            pinky_folded = cv2.norm((pinky_tip.x, pinky_tip.y), (pinky_mcp.x, pinky_mcp.y))

            if (thumb_wrist_distance > index_wrist_distance + threshold and 
                index_wrist_distance < middle_wrist_distance + threshold and 
                middle_wrist_distance < ring_wrist_distance + threshold and 
                ring_wrist_distance < pinky_wrist_distance + threshold):
                gesture_detected = gestures[0]  # Daumen hoch
            elif (thumb_wrist_distance < index_wrist_distance - threshold and 
                  thumb_tip.y > wrist.y and 
                  index_wrist_distance < middle_wrist_distance + threshold):
                gesture_detected = gestures[1]  # Daumen runter
            elif (thumb_folded < threshold and 
                  index_folded < threshold and 
                  middle_folded < threshold and 
                  ring_folded < threshold and 
                  pinky_folded < threshold):
                gesture_detected = gestures[2]  # Faust
            elif (index_wrist_distance > middle_wrist_distance + threshold and 
                  middle_wrist_distance < ring_wrist_distance + threshold and 
                  ring_wrist_distance < pinky_wrist_distance + threshold and 
                  thumb_wrist_distance < index_wrist_distance - threshold):
                gesture_detected = gestures[3]  # Zeigefinger
            elif (middle_wrist_distance > index_wrist_distance + threshold and 
                  middle_wrist_distance > ring_wrist_distance + threshold and 
                  index_wrist_distance < ring_wrist_distance + threshold and 
                  thumb_wrist_distance < middle_wrist_distance - threshold):
                gesture_detected = gestures[4]  # Stinkefinger
            elif (cv2.norm((thumb_tip.x, thumb_tip.y), (index_tip.x, index_tip.y)) < threshold and 
                  middle_folded < threshold and 
                  ring_folded < threshold and 
                  pinky_folded < threshold):
                gesture_detected = gestures[5]  # OK

    if gesture_detected:
        cv2.putText(frame, f"Geste: {gesture_detected}", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    else:
        cv2.putText(frame, "Keine Geste erkannt", (10, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

    cv2.imshow('Gestenerkennung', frame)
    if cv2.waitKey(1) & 0xFF == 27:
        break

cap.release()
cv2.destroyAllWindows()

Speichere den Code in einer Datei (z. B. gesture_recognition.py) und starte ihn mit python gesture_recognition.py.


Was macht der Code?

Der Code nutzt MediaPipe, um Handlandmarks (Punkte wie Fingerspitzen und Handgelenk) in Echtzeit zu erkennen. Basierend auf den Abständen zwischen diesen Punkten werden sechs Gesten erkannt:

  • Daumen hoch/runter: Position des Daumens relativ zu anderen Fingern.
  • Faust: Alle Finger sind gefaltet.
  • Zeigefinger/Stinkefinger: Nur ein Finger ist ausgestreckt.
  • OK: Daumen und Zeigefinger bilden einen Kreis.

Die Ergebnisse werden live im Webcam-Fenster angezeigt. Beachte jedoch: Die Erkennung ist relativ ungenau, da sie stark von Beleuchtung, Handposition und Schwellenwerten abhängt.


Einsatzszenarien

Hier sind einige Ideen, wie du die Gestenerkennung nutzen könntest:

  1. Spiele-Steuerung: Steuere einfache Spiele wie Pong mit Gesten statt Tastatur – z. B. Faust für „Pause“.
  2. Präsentations-Tool: Blättere in PowerPoint mit „Daumen hoch“ (vorwärts) oder „Daumen runter“ (zurück).
  3. Smart-Home-Steuerung: Schalte Lichter ein/aus oder dimme sie mit Gesten über eine Raspberry Pi-Integration.
  4. Lernprojekte: Nutze es als Basis für ein Schulprojekt über Computer Vision.

Grenzen und Verbesserungsmöglichkeiten

Die aktuelle Lösung ist ein guter Start, aber nicht perfekt. Hier sind einige Schwächen und Verbesserungsideen:

  • Ungenauigkeit: Die Erkennung basiert nur auf Abständen und kann bei ungewöhnlichen Handwinkeln oder schlechter Beleuchtung versagen. Verbesserung: Nutze Winkelberechnungen zwischen Fingern oder trainiere ein eigenes Modell mit TensorFlow.
  • Statische Schwellenwerte: Der threshold-Wert (0.1) passt nicht immer. Verbesserung: Dynamische Anpassung basierend auf Handgröße oder Kalibrierungsphase.
  • Begrenzte Gesten: Nur sechs Gesten werden erkannt. Verbesserung: Erweitere die Logik oder nutze Deep Learning für komplexere Gesten wie Gebärdensprache.
  • Performance: Bei schwacher Hardware kann die Echtzeit-Verarbeitung ruckeln. Verbesserung: Reduziere die Auflösung mit cv2.resize.

Alternativ kannst du auf andere Ansätze setzen, z. B.:


Schreibe einen Kommentar

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