dcrey7 commited on
Commit
ff490fa
·
verified ·
1 Parent(s): 441a3a0

Fix: inline self-contained MediaPipe pose (drop futheros.adapters dependency)

Browse files
Files changed (1) hide show
  1. futheros/pipeline.py +38 -5
futheros/pipeline.py CHANGED
@@ -271,11 +271,44 @@ def shooter_frame(holder, xy, goal, goal_f, n):
271
 
272
  # ----------------------------------------------------------------------------- pose
273
  _POSE = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  def _pose():
275
  global _POSE
276
  if _POSE is None:
277
- from .adapters.pose_mediapipe import MediaPipePose
278
- _POSE = MediaPipePose()
279
  return _POSE
280
 
281
 
@@ -289,10 +322,10 @@ def shooter_pose(clip, players, xy, kicker, kf, W, H):
289
  cap = cv2.VideoCapture(clip); cap.set(cv2.CAP_PROP_POS_FRAMES, kf); ok, fr = cap.read(); cap.release()
290
  if not ok or x1-x0 < 8 or y1-y0 < 8:
291
  return None, (x0, y0, x1, y1), "?"
292
- fp = _pose().estimate([fr[y0:y1, x0:x1]])[0]
293
- if fp.xy is None:
294
  return None, (x0, y0, x1, y1), "?"
295
- pts = fp.xy + np.array([x0, y0]); foot = "?"
296
  if not np.isnan(xy[kf, 0]):
297
  bx, by = xy[kf]
298
  foot = "L" if np.hypot(*(pts[L_ANKLE]-[bx, by])) < np.hypot(*(pts[R_ANKLE]-[bx, by])) else "R"
 
271
 
272
  # ----------------------------------------------------------------------------- pose
273
  _POSE = None
274
+ _POSE_URL = ("https://storage.googleapis.com/mediapipe-models/pose_landmarker/"
275
+ "pose_landmarker_full/float16/latest/pose_landmarker_full.task")
276
+ _POSE_FILE = "/tmp/pose_landmarker_full.task"
277
+
278
+
279
+ class _MPPose:
280
+ """Self-contained MediaPipe Tasks PoseLandmarker (2D image-plane landmarks only)."""
281
+
282
+ def __init__(self):
283
+ import urllib.request
284
+ import mediapipe as mp
285
+ from mediapipe.tasks import python
286
+ from mediapipe.tasks.python import vision
287
+ self._mp = mp
288
+ if not os.path.exists(_POSE_FILE):
289
+ urllib.request.urlretrieve(_POSE_URL, _POSE_FILE)
290
+ opts = vision.PoseLandmarkerOptions(
291
+ base_options=python.BaseOptions(model_asset_path=_POSE_FILE),
292
+ running_mode=vision.RunningMode.IMAGE, num_poses=1,
293
+ min_pose_detection_confidence=0.5, min_pose_presence_confidence=0.5,
294
+ min_tracking_confidence=0.5)
295
+ self._lm = vision.PoseLandmarker.create_from_options(opts)
296
+
297
+ def xy(self, frame_bgr):
298
+ h, w = frame_bgr.shape[:2]
299
+ img = self._mp.Image(image_format=self._mp.ImageFormat.SRGB,
300
+ data=np.ascontiguousarray(frame_bgr[:, :, ::-1]))
301
+ res = self._lm.detect(img)
302
+ if not res.pose_landmarks:
303
+ return None
304
+ lms = res.pose_landmarks[0]
305
+ return np.array([[lm.x * w, lm.y * h] for lm in lms], dtype=np.float32)
306
+
307
+
308
  def _pose():
309
  global _POSE
310
  if _POSE is None:
311
+ _POSE = _MPPose()
 
312
  return _POSE
313
 
314
 
 
322
  cap = cv2.VideoCapture(clip); cap.set(cv2.CAP_PROP_POS_FRAMES, kf); ok, fr = cap.read(); cap.release()
323
  if not ok or x1-x0 < 8 or y1-y0 < 8:
324
  return None, (x0, y0, x1, y1), "?"
325
+ fxy = _pose().xy(fr[y0:y1, x0:x1])
326
+ if fxy is None:
327
  return None, (x0, y0, x1, y1), "?"
328
+ pts = fxy + np.array([x0, y0]); foot = "?"
329
  if not np.isnan(xy[kf, 0]):
330
  bx, by = xy[kf]
331
  foot = "L" if np.hypot(*(pts[L_ANKLE]-[bx, by])) < np.hypot(*(pts[R_ANKLE]-[bx, by])) else "R"