SSense / pose_estimator.py
ZynkDev's picture
Upload 6 files
6d767ef verified
Raw History Blame Contribute Delete
2.52 kB
# MediaPipe Pose for AR overlay tab
from PIL import Image
import mediapipe as mp
import numpy as np
mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils
LANDMARK = mp_pose.PoseLandmark
TORSO_INDICES = [
LANDMARK.LEFT_SHOULDER.value,
LANDMARK.RIGHT_SHOULDER.value,
LANDMARK.LEFT_HIP.value,
LANDMARK.RIGHT_HIP.value,
]
def extract_pose_mediapipe(image_pil: Image.Image):
img_rgb = np.array(image_pil.convert("RGB"))
height, width = img_rgb.shape[:2]
with mp_pose.Pose(
static_image_mode=True,
model_complexity=1,
enable_segmentation=False,
min_detection_confidence=0.5,
min_tracking_confidence=0.5,
) as pose:
results = pose.process(img_rgb)
if not results.pose_landmarks:
return None
landmarks_raw = results.pose_landmarks.landmark
landmarks = {}
for idx, name in enumerate(LANDMARK):
px = int(landmarks_raw[idx].x * width)
py = int(landmarks_raw[idx].y * height)
landmarks[name.name] = (px, py)
skeleton_canvas = np.zeros_like(img_rgb)
mp_drawing.draw_landmarks(
skeleton_canvas,
results.pose_landmarks,
mp_pose.POSE_CONNECTIONS,
landmark_drawing_spec=mp_drawing.DrawingSpec(
color=(0, 255, 200), thickness=2, circle_radius=4
),
connection_drawing_spec=mp_drawing.DrawingSpec(color=(100, 180, 255), thickness=2),
)
torso_x = [landmarks_raw[idx].x * width for idx in TORSO_INDICES]
torso_y = [landmarks_raw[idx].y * height for idx in TORSO_INDICES]
pad_x = int((max(torso_x) - min(torso_x)) * 0.12)
pad_y_top = int((max(torso_y) - min(torso_y)) * 0.08)
pad_y_bottom = int((max(torso_y) - min(torso_y)) * 0.05)
x1 = max(0, int(min(torso_x)) - pad_x)
y1 = max(0, int(min(torso_y)) - pad_y_top)
x2 = min(width, int(max(torso_x)) + pad_x)
y2 = min(height, int(max(torso_y)) + pad_y_bottom)
return {
"landmarks": landmarks,
"skeleton_pil": Image.fromarray(skeleton_canvas),
"torso_box": (x1, y1, x2, y2),
"image_size": (width, height),
}
def draw_skeleton_overlay(image_pil: Image.Image, pose_data: dict, alpha: float = 0.6):
base = np.array(image_pil.convert("RGB")).astype(float)
skeleton = np.array(pose_data["skeleton_pil"].convert("RGB")).astype(float)
skeleton_mask = (skeleton.sum(axis=2) > 0).astype(float)[:, :, np.newaxis]
blended = base * (1 - skeleton_mask * alpha) + skeleton * skeleton_mask * alpha
return Image.fromarray(blended.astype(np.uint8))