Fix camera capture reliability and rewrite tracking for available mediapipe/hardware

This commit is contained in:
2026-07-31 14:01:06 +02:00
parent 2e6f444302
commit db5d09e156
12 changed files with 400 additions and 420 deletions
+39 -18
View File
@@ -1,7 +1,10 @@
import numpy as np
import cv2
import os
from PySide6.QtCore import QObject, QTimer
import mediapipe as mp
from mediapipe.tasks.python import BaseOptions
from mediapipe.tasks.python.vision import HandLandmarker, HandLandmarkerOptions, RunningMode
from Tbd.helper import Hand2D
from collections import defaultdict
from Helpers.HandUdpSender import HandUdpSender
@@ -9,6 +12,8 @@ from Helpers.HandUdpSender import HandUdpSender
import struct
import time
MODEL_PATH = os.path.join(os.path.dirname(__file__), "models", "hand_landmarker.task")
class TrackingController(QObject):
def __init__(self, cameraList, P_mats, logger=None, tick_ms=30):
super().__init__()
@@ -25,16 +30,20 @@ class TrackingController(QObject):
self.running = False
# init mediapipe here (or inject it)
self.mp_hands = mp.solutions.hands
self.hands = self.mp_hands.Hands(
static_image_mode=False,
max_num_hands=4,
model_complexity=1,
min_detection_confidence=0.5,
# MediaPipe's legacy solutions.hands API no longer exists on the
# installed mediapipe version, so hand detection runs on the newer
# Tasks API instead (IMAGE mode: each camera frame is detected
# independently, since frames from different cameras aren't a single
# monotonic video stream that VIDEO mode requires).
options = HandLandmarkerOptions(
base_options=BaseOptions(model_asset_path=MODEL_PATH),
running_mode=RunningMode.IMAGE,
num_hands=4,
min_hand_detection_confidence=0.5,
min_hand_presence_confidence=0.5,
min_tracking_confidence=0.5,
)
self.detector = HandLandmarker.create_from_options(options)
def start(self):
# Guard: need projections
@@ -45,6 +54,11 @@ class TrackingController(QObject):
if self.running:
return
for camera in self.cameraList:
if not camera.open():
if self.logger: self.logger.log(f"[Tracking] cam{camera.index}: failed to open, will be skipped.")
self.running = True
self.timer.start(self.tick_ms)
if self.logger: self.logger.log("[Tracking] Started")
@@ -54,6 +68,10 @@ class TrackingController(QObject):
return
self.running = False
self.timer.stop()
for camera in self.cameraList:
camera.close()
if self.logger: self.logger.log("[Tracking] Stopped")
def _tick(self):
@@ -81,30 +99,33 @@ class TrackingController(QObject):
def _detectHands_all_cameras(self):
out = []
for camera in self.cameraList:
if camera.capture is None:
continue
ok, frameBGR = camera.capture.read()
if not ok or frameBGR is None:
continue
h, w = frameBGR.shape[:2]
frameRGB = cv2.cvtColor(frameBGR, cv2.COLOR_BGR2RGB)
frameRGB.flags.writeable = False
hand_tracking_result = self.hands.process(frameRGB)
if not hand_tracking_result.multi_hand_landmarks:
mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=frameRGB)
result = self.detector.detect(mp_image)
if not result.hand_landmarks:
continue
handed = hand_tracking_result.multi_handedness
for hi, lm_list in enumerate(hand_tracking_result.multi_hand_landmarks):
for hi, lm_list in enumerate(result.hand_landmarks):
landmarks_px = np.array(
[[lm.x * w, lm.y * h] for lm in lm_list.landmark],
[[lm.x * w, lm.y * h] for lm in lm_list],
dtype=np.float32
)
label, score = "Unknown", 0.0
if hi < len(handed) and handed[hi].classification:
label = handed[hi].classification[0].label
score = handed[hi].classification[0].score
if hi < len(result.handedness) and result.handedness[hi]:
label = result.handedness[hi][0].category_name
score = result.handedness[hi][0].score
out.append(Hand2D(
camera_id=camera.index,
handedness=label,