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:
- Spiele-Steuerung: Steuere einfache Spiele wie Pong mit Gesten statt Tastatur – z. B. Faust für „Pause“.
- Präsentations-Tool: Blättere in PowerPoint mit „Daumen hoch“ (vorwärts) oder „Daumen runter“ (zurück).
- Smart-Home-Steuerung: Schalte Lichter ein/aus oder dimme sie mit Gesten über eine Raspberry Pi-Integration.
- 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.:
- YOLO: Für präzisere Objekterkennung, anpassbar auf Gesten.
- PyTorch: Trainiere ein eigenes Modell mit einem Datensatz wie Hand Gesture Recognition Database.
Schreibe einen Kommentar