Echtzeit-Gesichtserkennung mit OpenCVs YuNet
Die Gesichtserkennung in Echtzeit ist ein leistungsfähiges Werkzeug für die unterschiedlichsten Anwendungen, von der Sicherheitsüberwachung bis hin zu interaktiven Nutzererlebnissen. In diesem Beitrag zeigen wir, wie Sie in Python mit OpenCVs YuNet-Detektor, einem leichtgewichtigen Modell für effiziente CPU-Inferenz, eine Streaming-Pipeline zur Gesichtserkennung einrichten.
Warum Gesichtserkennung in Echtzeit?
Die Erkennung von Gesichtern in Echtzeit ermöglicht vielfältige Anwendungen, von Sicherheitssystemen bis hin zu interaktiven Installationen. Moderne Algorithmen zur Gesichtserkennung wie YuNet bieten eine robuste Erkennung bei gleichzeitig hoher Performance und eignen sich damit für Produktionsumgebungen.
Ihre Umgebung einrichten
Verwenden Sie Python 3.10+ und OpenCV 4.8+ für das YuNet-Modell vom März 2023. Installieren Sie Git LFS, bevor Sie das Modell-Repository klonen, und führen Sie die Beispiele im unten genannten Modellverzeichnis aus:
# Install required packages
python -m pip install 'opencv-python>=4.8,<5' numpy
# Download YuNet model
git lfs install
git clone https://github.com/opencv/opencv_zoo.git
cd opencv_zoo/models/face_detection_yunet/
git lfs pull --include='models/face_detection_yunet/face_detection_yunet_2023mar.onnx'
Verwenden Sie in dieser Umgebung nur eine einzige OpenCV-Python-Distribution. Das Webcam-Fenster setzt den oben genannten GUI-Build, ein funktionierendes Display und die Berechtigung für den Kamerazugriff voraus.
Eine einfache Streaming-Pipeline zur Gesichtserkennung aufbauen
Hier ist ein vollständiges Beispiel, das Video von Ihrer Webcam aufnimmt und jedes Bild mit YuNet verarbeitet:
import cv2
import numpy as np
# Initialize YuNet face detector
face_detector = cv2.FaceDetectorYN.create(
'face_detection_yunet_2023mar.onnx',
"",
(320, 320),
0.9, # score threshold
0.3, # nms threshold
5000 # top k
)
def draw_faces(frame, faces):
if faces is None:
return
for face in faces:
box = face[0:4].astype(np.int32)
cv2.rectangle(frame, (box[0], box[1]),
(box[0] + box[2], box[1] + box[3]),
(0, 255, 0), 2)
# Initialize webcam
cap = cv2.VideoCapture(0)
try:
if not cap.isOpened():
raise RuntimeError('Could not open webcam')
while True:
ret, frame = cap.read()
if not ret:
break
# Match the detector input to every frame
height, width = frame.shape[:2]
face_detector.setInputSize((width, height))
_, faces = face_detector.detect(frame)
draw_faces(frame, faces)
cv2.imshow('Real-time Face Detection', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
finally:
cap.release()
cv2.destroyAllWindows()
Dieses Skript initialisiert den YuNet-Detektor, erfasst Videobilder und zeichnet in Echtzeit Begrenzungsrahmen um erkannte Gesichter.
Fortgeschrittene Nutzung: mehrere Gesichter und Parameteranpassungen
YuNet bietet mehrere Parameter, um die Erkennungsleistung fein abzustimmen. Ersetzen Sie die oben stehende Initialisierung des Detektors durch diese Konfiguration und verwenden Sie anschließend den Block für Erkennung und Zeichnung innerhalb der Aufnahmeschleife; behalten Sie dabei die vorhandenen Importe und die Aufräumlogik bei:
# Advanced configuration
face_detector = cv2.FaceDetectorYN.create(
'face_detection_yunet_2023mar.onnx',
"",
(320, 320),
0.7, # Lower threshold for higher sensitivity
0.4, # Adjusted NMS threshold
10000 # Increased top k for more faces
)
# Error handling and face processing
try:
face_detector.setInputSize((frame.shape[1], frame.shape[0]))
_, faces = face_detector.detect(frame)
if faces is not None:
for face in faces:
confidence = face[14]
if confidence > 0.7: # Additional confidence filter
box = face[0:4].astype(np.int32)
landmarks = face[4:14].astype(np.int32).reshape(-1, 2)
# Draw face box
cv2.rectangle(frame, (box[0], box[1]),
(box[0] + box[2], box[1] + box[3]),
(0, 255, 0), 2)
# Draw landmarks
for landmark in landmarks:
cv2.circle(frame, tuple(landmark), 2, (0, 255, 255), -1)
except cv2.error as e:
raise RuntimeError('Face detection failed') from e
Jede Erkennung umfasst 15 Werte: vier Koordinaten des Begrenzungsrahmens, zehn Landmark-Koordinaten und den Konfidenzwert an Index 14, wie im OpenCV-Tutorial zur Gesichtserkennung dokumentiert.
Performance optimieren
So erreichen Sie optimale Performance in Echtzeit-Anwendungen:
-
Ändern Sie die Größe der Eingabebilder:
scale = 0.5 resized = cv2.resize(frame, None, fx=scale, fy=scale) face_detector.setInputSize((resized.shape[1], resized.shape[0])) _, faces = face_detector.detect(resized) if faces is not None: # Convert boxes and landmarks back to the original frame's coordinates. faces[:, 0:14:2] *= frame.shape[1] / resized.shape[1] faces[:, 1:14:2] *= frame.shape[0] / resized.shape[0] -
Geben Sie bei unabhängigen Bildern jedem Worker einen eigenen Detektor. Teilen Sie den veränderlichen Detektor nicht zwischen gleichzeitigen Aufrufen. Dieses begrenzte Beispiel verarbeitet zwei bereits erfasste Bilder; Streaming-Anwendungen benötigen zusätzlich eine begrenzte Queue oder eine Richtlinie, um Bilder zu verwerfen, wenn die Verarbeitung zurückfällt. Das Erstellen eines Detektors für jedes Bild verursacht Overhead; messen Sie daher, ob Nebenläufigkeit tatsächlich hilft:
from concurrent.futures import ThreadPoolExecutor def process_frame(frame): detector = cv2.FaceDetectorYN.create( 'face_detection_yunet_2023mar.onnx', '', (frame.shape[1], frame.shape[0]), 0.9, 0.3, 5000 ) _, faces = detector.detect(frame) return faces def detect_pair(frame_a, frame_b): with ThreadPoolExecutor(max_workers=2) as executor: futures = [executor.submit(process_frame, image.copy()) for image in (frame_a, frame_b)] return [future.result() for future in futures] -
Implementieren Sie bei Bedarf das Überspringen von Bildern. Ersetzen Sie im ersten Beispiel die Schleife innerhalb des Blocks
trydurch diese Schleife und behalten Sie dabei die Hilfsfunktiondraw_facessowie die Aufräumlogik infinallybei. Nur verarbeitete Bilder zeigen Begrenzungsrahmen; übersprungene Bilder werden ohne veraltete Erkennungen angezeigt:frame_count = 0 process_every = 2 # Process every second frame while True: ret, frame = cap.read() if not ret: break frame_count += 1 if frame_count % process_every == 0: face_detector.setInputSize((frame.shape[1], frame.shape[0])) _, faces = face_detector.detect(frame) draw_faces(frame, faces) cv2.imshow('Real-time Face Detection', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break
Praktischer Anwendungsfall: Sicherheitsüberwachung
Hier ist ein praktisches Beispiel für ein System zur Sicherheitsüberwachung, das erkannte Gesichter protokolliert:
import cv2
from datetime import datetime
import json
class FaceMonitor:
def __init__(self, log_file='face_detections.jsonl'):
self.log_file = log_file
self.face_detector = cv2.FaceDetectorYN.create(
'face_detection_yunet_2023mar.onnx',
"",
(320, 320),
0.9,
0.3,
5000
)
def log_detection(self, num_faces):
entry = {
'timestamp': datetime.now().isoformat(),
'faces_detected': num_faces
}
with open(self.log_file, 'a') as f:
json.dump(entry, f)
f.write('\n')
def monitor(self, frame):
self.face_detector.setInputSize((frame.shape[1], frame.shape[0]))
_, faces = self.face_detector.detect(frame)
if faces is not None:
self.log_detection(len(faces))
return faces
Hinweise zur Performance
Messen Sie Durchsatz und Speicherverbrauch auf Ihrer Zielhardware bei der tatsächlichen
Bildauflösung. Die Erkennungsqualität hängt außerdem von der Gesichtsgröße, der Beleuchtung,
Verdeckungen und den Schwellenwerteinstellungen ab. Das
YuNet-Modell-Repository
veröffentlicht Benchmark-Ergebnisse; diese Ergebnisse garantieren nicht dieselbe Genauigkeit oder
Bildrate für einen Webcam-Feed. Verwenden Sie pro Verarbeitungs-Thread eine eigene Instanz von
FaceMonitor.
Fazit
Mit modernen Werkzeugen wie OpenCVs YuNet-Detektor ist die Umsetzung von Gesichtserkennung in Echtzeit zugänglicher geworden. Die Kombination aus hoher Performance und Genauigkeit macht ihn zu einer ausgezeichneten Wahl für die unterschiedlichsten Anwendungen. Wenn Sie automatisierte Lösungen zur Bildanalyse im großen Maßstab erkunden möchten, werfen Sie einen Blick in die Dokumentation zum KI-Service von Transloadit.
