File size: 10,056 Bytes
1e91e1d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4155984
 
 
1e91e1d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4155984
1e91e1d
 
 
4155984
1e91e1d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4155984
 
 
1e91e1d
 
 
 
 
 
 
 
 
 
 
 
 
4155984
1e91e1d
 
 
4155984
1e91e1d
 
 
 
4155984
1e91e1d
4155984
1e91e1d
 
 
 
 
 
 
 
 
4155984
1e91e1d
4155984
1e91e1d
 
 
 
 
 
 
 
 
4155984
1e91e1d
4155984
 
 
1e91e1d
 
 
 
 
 
 
 
 
4155984
1e91e1d
 
4155984
1e91e1d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
import mediapipe as mp
import numpy as np
import cv2
from typing import List, Tuple, Optional

class PoseDetector:
    def __init__(self):
        self.mp_pose = mp.solutions.pose
        self.mp_drawing = mp.solutions.drawing_utils
        self.mp_drawing_styles = mp.solutions.drawing_styles

        # Define pose connections for smooth animation
        self.pose_connections = [
            # Spine Chain
            (self.mp_pose.PoseLandmark.NOSE.value, self.mp_pose.PoseLandmark.LEFT_SHOULDER.value),
            (self.mp_pose.PoseLandmark.NOSE.value, self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value),
            (self.mp_pose.PoseLandmark.LEFT_SHOULDER.value, self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value),
            (self.mp_pose.PoseLandmark.LEFT_SHOULDER.value, self.mp_pose.PoseLandmark.LEFT_HIP.value),
            (self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value, self.mp_pose.PoseLandmark.RIGHT_HIP.value),
            (self.mp_pose.PoseLandmark.LEFT_HIP.value, self.mp_pose.PoseLandmark.RIGHT_HIP.value),
            
            # Left Arm Chain
            (self.mp_pose.PoseLandmark.LEFT_SHOULDER.value, self.mp_pose.PoseLandmark.LEFT_ELBOW.value),
            (self.mp_pose.PoseLandmark.LEFT_ELBOW.value, self.mp_pose.PoseLandmark.LEFT_WRIST.value),
            (self.mp_pose.PoseLandmark.LEFT_WRIST.value, self.mp_pose.PoseLandmark.LEFT_THUMB.value),
            
            # Right Arm Chain
            (self.mp_pose.PoseLandmark.RIGHT_SHOULDER.value, self.mp_pose.PoseLandmark.RIGHT_ELBOW.value),
            (self.mp_pose.PoseLandmark.RIGHT_ELBOW.value, self.mp_pose.PoseLandmark.RIGHT_WRIST.value),
            (self.mp_pose.PoseLandmark.RIGHT_WRIST.value, self.mp_pose.PoseLandmark.RIGHT_THUMB.value),
            
            # Left Leg Chain
            (self.mp_pose.PoseLandmark.LEFT_HIP.value, self.mp_pose.PoseLandmark.LEFT_KNEE.value),
            (self.mp_pose.PoseLandmark.LEFT_KNEE.value, self.mp_pose.PoseLandmark.LEFT_ANKLE.value),
            (self.mp_pose.PoseLandmark.LEFT_ANKLE.value, self.mp_pose.PoseLandmark.LEFT_FOOT_INDEX.value),
            
            # Right Leg Chain
            (self.mp_pose.PoseLandmark.RIGHT_HIP.value, self.mp_pose.PoseLandmark.RIGHT_KNEE.value),
            (self.mp_pose.PoseLandmark.RIGHT_KNEE.value, self.mp_pose.PoseLandmark.RIGHT_ANKLE.value),
            (self.mp_pose.PoseLandmark.RIGHT_ANKLE.value, self.mp_pose.PoseLandmark.RIGHT_FOOT_INDEX.value),
        ]

        # Drawing specifications
        self.landmark_drawing_spec = self.mp_drawing.DrawingSpec(
            color=(0, 255, 0),  # Green color
            thickness=2,
            circle_radius=2
        )
        self.connection_drawing_spec = self.mp_drawing.DrawingSpec(
            color=(255, 255, 0),  # Yellow color
            thickness=2
        )

    def detect(self, image, manual_corrections=None) -> Tuple[Optional[np.ndarray], np.ndarray]:
        """
        Detect pose in the given image
        Args:
            image: Input image
            manual_corrections: Dictionary of landmark indices and their corrected positions
        Returns: (landmarks, annotated_image)
        """
        # (Основная логика не изменена)
        pass

    def draw_corrected_pose(self, image: np.ndarray, corrected_joints: dict) -> np.ndarray:
        """Draw pose with manually corrected joint positions"""
        annotated_image = image.copy()
        h, w = image.shape[:2]
        
        # Draw connections
        for start_name, end_name in self.pose_connections:
            if start_name in corrected_joints and end_name in corrected_joints:
                start_pos = corrected_joints[start_name]['position']
                end_pos = corrected_joints[end_name]['position']
                
                start_px = (int(start_pos[0] * w), int(start_pos[1] * h))
                end_px = (int(end_pos[0] * w), int(end_pos[1] * h))
                
                cv2.line(annotated_image, start_px, end_px, (0, 255, 0), 3)
        
        # Draw joints (уменьшенный радиус с 5 до 3)
        for joint_name, joint_data in corrected_joints.items():
            pos = joint_data['position']
            px_pos = (int(pos[0] * w), int(pos[1] * h))
            cv2.circle(annotated_image, px_pos, 3, (0, 255, 255), -1)
            cv2.putText(annotated_image, joint_name, 
                       (px_pos[0], px_pos[1] - 10),
                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
                       
        return annotated_image

    def _draw_smooth_connections(self, image: np.ndarray, landmarks, connections: List[Tuple[int, int]]):
        """Draw smooth connections between landmarks in Maya-like style"""
        h, w = image.shape[:2]
        
        bone_names = {
            0: "Head",
            11: "Neck",
            12: "Spine2",
            23: "Hips",
            24: "Spine",
            13: "LeftArm",
            14: "RightArm",
            15: "LeftForeArm",
            16: "RightForeArm",
            25: "LeftLeg",
            26: "RightLeg",
            27: "LeftFoot",
            28: "RightFoot",
            31: "LeftToeBase",
            32: "RightToeBase"
        }

        joint_color = (0, 255, 255)  # Cyan
        bone_color = (0, 255, 0)    # Green
        text_color = (255, 255, 255) # White

        for connection in connections:
            start_idx, end_idx = connection
            start_point = landmarks.landmark[start_idx]
            end_point = landmarks.landmark[end_idx]
            start_pos = (int(start_point.x * w), int(start_point.y * h))
            end_pos = (int(end_point.x * w), int(end_point.y * h))

            cv2.line(
                image,
                start_pos,
                end_pos,
                bone_color,
                3,
                cv2.LINE_AA
            )

            # Рисуем суставы с уменьшенным радиусом (с 5 до 3)
            for pos, idx in [(start_pos, start_idx), (end_pos, end_idx)]:
                cv2.circle(
                    image,
                    pos,
                    3,
                    joint_color,
                    -1,
                    cv2.LINE_AA
                )
                if idx in bone_names:
                    text_pos = (pos[0], pos[1] - 10)
                    cv2.putText(
                        image,
                        bone_names[idx],
                        text_pos,
                        cv2.FONT_HERSHEY_SIMPLEX,
                        0.5,
                        text_color,
                        1,
                        cv2.LINE_AA
                    )

    def detect_video_frame(self, frame):
        """
        Detect pose in video frame with optimized parameters for video
        """
        with self.mp_pose.Pose(
            static_image_mode=False,
            model_complexity=2,
            smooth_landmarks=True,
            min_detection_confidence=0.5,   # Повышенный порог для большей точности
            min_tracking_confidence=0.5,      # Повышенный порог для большей точности
            enable_segmentation=False
        ) as pose:
            image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            results = pose.process(image_rgb)
            
            annotated_frame = frame.copy()
            
            if results.pose_landmarks:
                self.landmark_drawing_spec.thickness = 6
                self.connection_drawing_spec.thickness = 5
                self.landmark_drawing_spec.circle_radius = 2  # Используем меньший радиус для видео
                
                if hasattr(self, 'previous_landmarks'):
                    smoothing_factor = 0.8
                    for i, landmark in enumerate(results.pose_landmarks.landmark):
                        if self.previous_landmarks is not None:
                            if landmark.visibility < 0.7 or self.previous_landmarks[i].visibility > 0.8:
                                landmark.x = smoothing_factor * self.previous_landmarks[i].x + (1 - smoothing_factor) * landmark.x
                                landmark.y = smoothing_factor * self.previous_landmarks[i].y + (1 - smoothing_factor) * landmark.y
                                landmark.z = smoothing_factor * self.previous_landmarks[i].z + (1 - smoothing_factor) * landmark.z
                                landmark.visibility = max(landmark.visibility, self.previous_landmarks[i].visibility * 0.9)
                
                self.previous_landmarks = results.pose_landmarks.landmark
                
                self._draw_smooth_connections(
                    annotated_frame,
                    results.pose_landmarks,
                    self.pose_connections
                )
                
                self.mp_drawing.draw_landmarks(
                    image=annotated_frame,
                    landmark_list=results.pose_landmarks,
                    connections=self.mp_pose.POSE_CONNECTIONS,
                    landmark_drawing_spec=self.landmark_drawing_spec,
                    connection_drawing_spec=self.connection_drawing_spec
                )
                
                landmarks = np.array([[lm.x, lm.y, lm.z] for lm in results.pose_landmarks.landmark])
                return landmarks, annotated_frame
            elif hasattr(self, 'previous_landmarks') and self.previous_landmarks is not None:
                results.pose_landmarks = type('obj', (object,), {'landmark': self.previous_landmarks})
                self._draw_smooth_connections(
                    annotated_frame,
                    results.pose_landmarks,
                    self.pose_connections
                )
                landmarks = np.array([[lm.x, lm.y, lm.z] for lm in self.previous_landmarks])
                return landmarks, annotated_frame
                
            return None, annotated_frame