David Driscoll commited on
Commit
568b799
·
1 Parent(s): 1b67eea
Files changed (2) hide show
  1. app.py +120 -0
  2. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import mediapipe as mp
3
+ import numpy as np
4
+ import gradio as gr
5
+
6
+ # Initialize MediaPipe Pose.
7
+ mp_pose = mp.solutions.pose
8
+ pose = mp_pose.Pose(
9
+ static_image_mode=False,
10
+ model_complexity=1,
11
+ enable_segmentation=False,
12
+ min_detection_confidence=0.5,
13
+ min_tracking_confidence=0.5
14
+ )
15
+
16
+ # Initialize MediaPipe Face Mesh.
17
+ mp_face_mesh = mp.solutions.face_mesh
18
+ face_mesh = mp_face_mesh.FaceMesh(
19
+ static_image_mode=False,
20
+ max_num_faces=1,
21
+ refine_landmarks=True,
22
+ min_detection_confidence=0.5,
23
+ min_tracking_confidence=0.5
24
+ )
25
+
26
+ def process_frame(image):
27
+ """
28
+ Processes an input image (from the webcam) by:
29
+ 1. Converting from RGB (Gradio default) to BGR for OpenCV.
30
+ 2. Flipping the frame for a mirror view.
31
+ 3. Creating a black background.
32
+ 4. Using MediaPipe Pose to draw body landmarks (excluding facial parts) and compute the shoulder center.
33
+ 5. Using MediaPipe Face Mesh to draw the full facial mesh and extract the chin point.
34
+ 6. Drawing a neck line from the shoulder center to the chin.
35
+ 7. Converting the result back to RGB for display.
36
+ """
37
+ # Convert the input image from RGB (Gradio default) to BGR.
38
+ frame = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
39
+
40
+ # Flip the frame horizontally for a mirror view.
41
+ frame = cv2.flip(frame, 1)
42
+
43
+ # Create a black background image of the same size.
44
+ output = np.zeros_like(frame)
45
+
46
+ # Convert frame to RGB for MediaPipe processing.
47
+ rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
48
+
49
+ # --- Body Posture Analysis using MediaPipe Pose ---
50
+ pose_results = pose.process(rgb_frame)
51
+ shoulder_center = None
52
+ if pose_results.pose_landmarks:
53
+ h, w, _ = frame.shape
54
+ landmarks = [(int(lm.x * w), int(lm.y * h)) for lm in pose_results.pose_landmarks.landmark]
55
+
56
+ # Draw body skeleton (only drawing non-facial landmarks, i.e. indices 11 and above).
57
+ for connection in mp_pose.POSE_CONNECTIONS:
58
+ start_idx, end_idx = connection
59
+ if start_idx >= 11 and end_idx >= 11:
60
+ if start_idx < len(landmarks) and end_idx < len(landmarks):
61
+ cv2.line(output, landmarks[start_idx], landmarks[end_idx], (255, 255, 0), 2)
62
+
63
+ # Draw landmarks as yellow circles.
64
+ for i, pt in enumerate(landmarks):
65
+ if i >= 11:
66
+ cv2.circle(output, pt, 3, (255, 255, 0), -1)
67
+
68
+ # Calculate shoulder center using landmarks 11 (left shoulder) and 12 (right shoulder).
69
+ if len(landmarks) > 12:
70
+ left_shoulder = landmarks[11]
71
+ right_shoulder = landmarks[12]
72
+ shoulder_center = ((left_shoulder[0] + right_shoulder[0]) // 2,
73
+ (left_shoulder[1] + right_shoulder[1]) // 2)
74
+ cv2.circle(output, shoulder_center, 4, (0, 255, 255), -1)
75
+
76
+ # --- Facemesh Analysis using MediaPipe Face Mesh ---
77
+ chin_point = None
78
+ fm_results = face_mesh.process(rgb_frame)
79
+ if fm_results.multi_face_landmarks:
80
+ for face_landmarks in fm_results.multi_face_landmarks:
81
+ h, w, _ = frame.shape
82
+ fm_points = [(int(lm.x * w), int(lm.y * h)) for lm in face_landmarks.landmark]
83
+
84
+ # Draw red lines connecting facial landmarks.
85
+ for connection in mp_face_mesh.FACEMESH_TESSELATION:
86
+ start_idx, end_idx = connection
87
+ if start_idx < len(fm_points) and end_idx < len(fm_points):
88
+ cv2.line(output, fm_points[start_idx], fm_points[end_idx], (0, 0, 255), 1)
89
+
90
+ # Draw green dots for each facial landmark.
91
+ for pt in fm_points:
92
+ cv2.circle(output, pt, 2, (0, 255, 0), -1)
93
+
94
+ # Extract the chin point (landmark 152 is generally at the bottom of the chin).
95
+ if len(face_landmarks.landmark) > 152:
96
+ lm = face_landmarks.landmark[152]
97
+ chin_point = (int(lm.x * w), int(lm.y * h))
98
+ cv2.circle(output, chin_point, 4, (0, 0, 255), -1)
99
+ break # Process only the first detected face.
100
+
101
+ # --- Draw the Neck Line ---
102
+ if shoulder_center and chin_point:
103
+ cv2.line(output, shoulder_center, chin_point, (0, 255, 255), 2)
104
+
105
+ # Convert the processed image back to RGB for display.
106
+ output_rgb = cv2.cvtColor(output, cv2.COLOR_BGR2RGB)
107
+ return output_rgb
108
+
109
+ # Create the Gradio interface.
110
+ iface = gr.Interface(
111
+ fn=process_frame,
112
+ inputs=gr.Image(source="webcam", type="numpy", label="Webcam"),
113
+ outputs=gr.Image(type="numpy", label="Processed Output"),
114
+ live=True,
115
+ title="Body Posture & Neck Analysis (No Face Pose)",
116
+ description="Webcam-based analysis using MediaPipe Pose and Face Mesh."
117
+ )
118
+
119
+ # Launch the Gradio app.
120
+ iface.launch()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ opencv-python
2
+ mediapipe
3
+ numpy
4
+ gradio
5
+ pillow
6
+ protobuf==3.20.*