File size: 5,039 Bytes
cca6a52
 
cfbaa51
 
 
cca6a52
 
4cdc77a
cca6a52
1ca9b28
 
 
cca6a52
 
 
1ca9b28
cca6a52
 
 
1ca9b28
 
cca6a52
 
 
 
 
 
89a012c
cca6a52
1ca9b28
 
 
cca6a52
 
 
 
 
 
1ca9b28
 
 
 
 
 
 
89a012c
1ca9b28
 
 
 
89a012c
1ca9b28
 
 
 
 
 
 
cca6a52
 
 
 
1ca9b28
cca6a52
1ca9b28
 
 
 
cca6a52
89a012c
1ca9b28
 
cca6a52
 
89a012c
cca6a52
 
 
89a012c
4cdc77a
89a012c
 
 
 
cca6a52
1ca9b28
cca6a52
4cdc77a
89a012c
4cdc77a
cca6a52
1ca9b28
89a012c
 
 
 
 
 
cca6a52
89a012c
 
 
 
 
 
 
 
 
 
 
 
 
 
cca6a52
89a012c
cca6a52
1ca9b28
cca6a52
89a012c
cca6a52
 
 
89a012c
1ca9b28
89a012c
 
1ca9b28
89a012c
 
 
 
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
import math
import numpy as np

from CPR_Module.Common.keypoints import CocoKeypoints
from CPR_Module.Common.logging_config import cpr_logger

class PostureAnalyzer:
    """Analyzes the Rescuer's posture during CPR based on the rescuer's keypoints and the patient's chest region."""
    
    def __init__(self, right_arm_angle_threshold, left_arm_angle_threshold, wrist_distance_threshold, history_length_to_average):
        self.history_length_to_average = history_length_to_average
        
        self.right_arm_angles = []
        self.left_arm_angles = []
        self.wrist_distances = []
        
        self.right_arm_angle_threshold = right_arm_angle_threshold
        self.left_arm_angle_threshold = left_arm_angle_threshold
        self.wrist_distance_threshold = wrist_distance_threshold
        
    def _calculate_angle(self, a, b, c):
        """Calculate angle between three points"""
        try:
            ang = math.degrees(math.atan2(c[1]-b[1], c[0]-b[0]) - 
                         math.atan2(a[1]-b[1], a[0]-b[0]))
            return ang + 360 if ang < 0 else ang
        except Exception as e:
            cpr_logger.error(f"Angle calculation error: {e}")
            return 0
    
    def _check_bended_right_arm(self, keypoints):
        """Check for right arm bending (returns warning)"""
        warnings = []
        try:
            shoulder = keypoints[CocoKeypoints.RIGHT_SHOULDER.value]
            elbow = keypoints[CocoKeypoints.RIGHT_ELBOW.value]
            wrist = keypoints[CocoKeypoints.RIGHT_WRIST.value]
            
            right_angle = self._calculate_angle(wrist, elbow, shoulder)
            
            self.right_arm_angles.append(right_angle)

            avg_right = np.mean(self.right_arm_angles[-self.history_length_to_average:] if self.right_arm_angles else 0)

            if avg_right > self.right_arm_angle_threshold:
                warnings.append("Right arm bent!")

            return warnings
                
        except Exception as e:
            cpr_logger.error(f"Right arm check error: {e}")
        
        return warnings
    
    def _check_bended_left_arm(self, keypoints):
        """Check for left arm bending (returns warning)"""
        warnings = []
        try:
            shoulder = keypoints[CocoKeypoints.LEFT_SHOULDER.value]
            elbow = keypoints[CocoKeypoints.LEFT_ELBOW.value]
            wrist = keypoints[CocoKeypoints.LEFT_WRIST.value]
            
            left_angle = self._calculate_angle(wrist, elbow, shoulder)
            
            self.left_arm_angles.append(left_angle)

            avg_left = np.mean(self.left_arm_angles[-self.history_length_to_average:] if self.left_arm_angles else 0)

            if avg_left < self.left_arm_angle_threshold:
                warnings.append("Left arm bent!")

            return warnings
                
        except Exception as e:
            cpr_logger.error(f"Left arm check error: {e}")
        
        return warnings

    def _check_hands_on_chest(self, keypoints, chest_params):
        """Check if both hands are on the chest (returns warnings)"""

        # Get the wrist keypoints
        left_wrist = keypoints[CocoKeypoints.LEFT_WRIST.value]
        right_wrist = keypoints[CocoKeypoints.RIGHT_WRIST.value]

        warnings = []
        try:
            # Fallback
            if chest_params is None:
                return ["Both hands not on chest!"]
            
            cx, cy, cw, ch = chest_params
            left_in = right_in = False

            # Check left hand
            if left_wrist is not None:
                left_in = (cx - cw/2 < left_wrist[0] < cx + cw/2) and \
                          (cy - ch/2 < left_wrist[1] < cy + ch/2)
            
            # Check right hand
            if right_wrist is not None:
                right_in = (cx - cw/2 < right_wrist[0] < cx + cw/2) and \
                            (cy - ch/2 < right_wrist[1] < cy + ch/2)

            # Determine warnings
            if not left_in and not right_in:
                warnings.append("Both hands not on chest!")
            else:
                if not left_in:
                    warnings.append("Left hand not on chest!")
                if not right_in:
                    warnings.append("Right hand not on chest!")

        except Exception as e:
            cpr_logger.error(f"Hands check error: {e}")
        
        return warnings

    def validate_posture(self, keypoints, chest_params):
        """Run all posture validations (returns aggregated warnings)"""
        warnings = []

        warnings += self._check_hands_on_chest(keypoints, chest_params)

        if ("Right hand not on chest!" not in warnings) and ("Both hands not on chest!" not in warnings):
            warnings += self._check_bended_right_arm(keypoints)
        
        if ("Left hand not on chest!" not in warnings) and ("Both hands not on chest!" not in warnings):
            warnings += self._check_bended_left_arm(keypoints)
       
        return warnings