Spaces:
Build error
Build error
| import cv2 | |
| import mediapipe as mp | |
| import numpy as np | |
| import gradio as gr | |
| # Initialize MediaPipe Pose. | |
| mp_pose = mp.solutions.pose | |
| pose = mp_pose.Pose( | |
| static_image_mode=False, | |
| model_complexity=1, | |
| enable_segmentation=False, | |
| min_detection_confidence=0.5, | |
| min_tracking_confidence=0.5 | |
| ) | |
| # Initialize MediaPipe Face Mesh. | |
| mp_face_mesh = mp.solutions.face_mesh | |
| face_mesh = mp_face_mesh.FaceMesh( | |
| static_image_mode=False, | |
| max_num_faces=1, | |
| refine_landmarks=True, | |
| min_detection_confidence=0.5, | |
| min_tracking_confidence=0.5 | |
| ) | |
| def process_frame(image): | |
| """ | |
| Processes an input image (from the webcam) by: | |
| 1. Converting from RGB (Gradio default) to BGR for OpenCV. | |
| 2. Flipping the frame for a mirror view. | |
| 3. Creating a black background. | |
| 4. Using MediaPipe Pose to draw body landmarks (excluding facial parts) and compute the shoulder center. | |
| 5. Using MediaPipe Face Mesh to draw the full facial mesh and extract the chin point. | |
| 6. Drawing a neck line from the shoulder center to the chin. | |
| 7. Converting the result back to RGB for display. | |
| """ | |
| # Convert the input image from RGB (Gradio default) to BGR. | |
| frame = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) | |
| # Flip the frame horizontally for a mirror view. | |
| frame = cv2.flip(frame, 1) | |
| # Create a black background image of the same size. | |
| output = np.zeros_like(frame) | |
| # Convert frame to RGB for MediaPipe processing. | |
| rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
| # --- Body Posture Analysis using MediaPipe Pose --- | |
| pose_results = pose.process(rgb_frame) | |
| shoulder_center = None | |
| if pose_results.pose_landmarks: | |
| h, w, _ = frame.shape | |
| landmarks = [(int(lm.x * w), int(lm.y * h)) for lm in pose_results.pose_landmarks.landmark] | |
| # Draw body skeleton (only drawing non-facial landmarks, i.e. indices 11 and above). | |
| for connection in mp_pose.POSE_CONNECTIONS: | |
| start_idx, end_idx = connection | |
| if start_idx >= 11 and end_idx >= 11: | |
| if start_idx < len(landmarks) and end_idx < len(landmarks): | |
| cv2.line(output, landmarks[start_idx], landmarks[end_idx], (255, 255, 0), 2) | |
| # Draw landmarks as yellow circles. | |
| for i, pt in enumerate(landmarks): | |
| if i >= 11: | |
| cv2.circle(output, pt, 3, (255, 255, 0), -1) | |
| # Calculate shoulder center using landmarks 11 (left shoulder) and 12 (right shoulder). | |
| if len(landmarks) > 12: | |
| left_shoulder = landmarks[11] | |
| right_shoulder = landmarks[12] | |
| shoulder_center = ((left_shoulder[0] + right_shoulder[0]) // 2, | |
| (left_shoulder[1] + right_shoulder[1]) // 2) | |
| cv2.circle(output, shoulder_center, 4, (0, 255, 255), -1) | |
| # --- Facemesh Analysis using MediaPipe Face Mesh --- | |
| chin_point = None | |
| fm_results = face_mesh.process(rgb_frame) | |
| if fm_results.multi_face_landmarks: | |
| for face_landmarks in fm_results.multi_face_landmarks: | |
| h, w, _ = frame.shape | |
| fm_points = [(int(lm.x * w), int(lm.y * h)) for lm in face_landmarks.landmark] | |
| # Draw red lines connecting facial landmarks. | |
| for connection in mp_face_mesh.FACEMESH_TESSELATION: | |
| start_idx, end_idx = connection | |
| if start_idx < len(fm_points) and end_idx < len(fm_points): | |
| cv2.line(output, fm_points[start_idx], fm_points[end_idx], (0, 0, 255), 1) | |
| # Draw green dots for each facial landmark. | |
| for pt in fm_points: | |
| cv2.circle(output, pt, 2, (0, 255, 0), -1) | |
| # Extract the chin point (landmark 152 is generally at the bottom of the chin). | |
| if len(face_landmarks.landmark) > 152: | |
| lm = face_landmarks.landmark[152] | |
| chin_point = (int(lm.x * w), int(lm.y * h)) | |
| cv2.circle(output, chin_point, 4, (0, 0, 255), -1) | |
| break # Process only the first detected face. | |
| # --- Draw the Neck Line --- | |
| if shoulder_center and chin_point: | |
| cv2.line(output, shoulder_center, chin_point, (0, 255, 255), 2) | |
| # Convert the processed image back to RGB for display. | |
| output_rgb = cv2.cvtColor(output, cv2.COLOR_BGR2RGB) | |
| return output_rgb | |
| # Create the Gradio interface. | |
| iface = gr.Interface( | |
| fn=process_frame, | |
| inputs=gr.Image(source="webcam", type="numpy", label="Webcam"), | |
| outputs=gr.Image(type="numpy", label="Processed Output"), | |
| live=True, | |
| title="Body Posture & Neck Analysis (No Face Pose)", | |
| description="Webcam-based analysis using MediaPipe Pose and Face Mesh." | |
| ) | |
| # Launch the Gradio app. | |
| iface.launch() | |