ivorobyev commited on
Commit
2ba6916
·
verified ·
1 Parent(s): 2754f03

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +96 -110
src/streamlit_app.py CHANGED
@@ -1,129 +1,115 @@
1
  import streamlit as st
2
  import cv2
3
  import numpy as np
 
4
  import mediapipe as mp
5
- from PIL import Image
 
6
 
7
- # Initialize MediaPipe
8
  mp_pose = mp.solutions.pose
9
  mp_drawing = mp.solutions.drawing_utils
10
 
11
- # Configure page
12
- st.set_page_config(layout="wide")
13
- st.title("📷 Posture Analysis App")
14
-
15
- # Initialize session state
16
- if 'camera_on' not in st.session_state:
17
- st.session_state.camera_on = False
18
- if 'posture_status' not in st.session_state:
19
- st.session_state.posture_status = "Please enable camera"
20
-
21
- def analyze_posture(image):
22
- """Analyze posture using MediaPipe"""
23
- with mp_pose.Pose(
24
- min_detection_confidence=0.5,
25
- min_tracking_confidence=0.5,
26
- model_complexity=1
27
- ) as pose:
28
-
29
- image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
30
- results = pose.process(image_rgb)
31
-
32
- annotated_image = image.copy()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  if results.pose_landmarks:
 
34
  mp_drawing.draw_landmarks(
35
- annotated_image,
36
- results.pose_landmarks,
37
- mp_pose.POSE_CONNECTIONS,
38
  mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2),
39
  mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)
40
  )
41
- posture_status = check_posture(results.pose_landmarks, image.shape)
 
42
  else:
43
- posture_status = "No pose detected"
44
-
45
- return annotated_image, posture_status
46
-
47
- def check_posture(landmarks, image_shape):
48
- """Analyze body landmarks and generate posture report"""
49
- h, w, _ = image_shape
50
-
51
- # Get key points
52
- left_shoulder = landmarks.landmark[mp_pose.PoseLandmark.LEFT_SHOULDER]
53
- right_shoulder = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_SHOULDER]
54
- left_hip = landmarks.landmark[mp_pose.PoseLandmark.LEFT_HIP]
55
- right_hip = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_HIP]
56
- left_ear = landmarks.landmark[mp_pose.PoseLandmark.LEFT_EAR]
57
- right_ear = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_EAR]
58
- nose = landmarks.landmark[mp_pose.PoseLandmark.NOSE]
59
-
60
- # Determine posture
61
- sitting = left_hip.y < left_shoulder.y + 0.1 or right_hip.y < right_shoulder.y + 0.1
62
-
63
- messages = []
64
-
65
- # Forward head check
66
- head_forward = (left_ear.y > left_shoulder.y + 0.1 or right_ear.y > right_shoulder.y + 0.1) and \
67
- (nose.y > left_shoulder.y or nose.y > right_shoulder.y)
68
- if head_forward:
69
- messages.append("• Forward head tilt detected")
70
-
71
- # Shoulders check
72
- shoulders_rounded = left_shoulder.x > left_hip.x + 0.05 or right_shoulder.x < right_hip.x - 0.05
73
- if shoulders_rounded:
74
- messages.append("• Rounded shoulders detected")
75
-
76
- # Side tilt check
77
- shoulder_diff = abs(left_shoulder.y - right_shoulder.y)
78
- hip_diff = abs(left_hip.y - right_hip.y)
79
- if shoulder_diff > 0.05 or hip_diff > 0.05:
80
- messages.append("• Body leaning to one side")
81
-
82
- # Generate report
83
- if messages:
84
- report = [
85
- f"**{'Sitting' if sitting else 'Standing'} posture issues:**",
86
- *messages,
87
- "\n**Recommendations:**",
88
- "• Keep head straight",
89
- "• Pull shoulders back",
90
- "• Maintain straight back",
91
- "• Sit on sitting bones"
92
- ]
93
- else:
94
- report = [
95
- f"**Excellent {'sitting' if sitting else 'standing'} posture!**",
96
- "\n**Tips:**",
97
- "• Continue monitoring your posture"
98
- ]
99
-
100
- return "\n\n".join(report)
101
 
102
  def main():
103
- col1, col2 = st.columns([2, 1])
104
-
105
- with col1:
106
- st.header("Camera View")
107
-
108
- # Camera toggle
109
- if st.button("Enable Camera" if not st.session_state.camera_on else "Disable Camera"):
110
- st.session_state.camera_on = not st.session_state.camera_on
111
- st.rerun()
112
-
113
- if st.session_state.camera_on:
114
- # Placeholder for local camera implementation
115
- demo_image = np.zeros((480, 640, 3), dtype=np.uint8)
116
- st.image(demo_image, caption="Camera feed placeholder")
117
- st.warning("For full camera functionality, please run locally")
118
-
119
- # Simulate analysis
120
- if st.button("Analyze Current Frame"):
121
- _, posture_status = analyze_posture(demo_image)
122
- st.session_state.posture_status = posture_status
123
-
124
- with col2:
125
- st.header("Analysis Results")
126
- st.markdown(st.session_state.posture_status)
127
 
128
  if __name__ == "__main__":
129
  main()
 
1
  import streamlit as st
2
  import cv2
3
  import numpy as np
4
+ from streamlit_webrtc import webrtc_streamer, VideoProcessorBase
5
  import mediapipe as mp
6
+ import av
7
+ from collections import deque
8
 
9
+ # Инициализация MediaPipe Pose
10
  mp_pose = mp.solutions.pose
11
  mp_drawing = mp.solutions.drawing_utils
12
 
13
+ class PoseProcessor(VideoProcessorBase):
14
+ def __init__(self):
15
+ self.pose = mp_pose.Pose(min_detection_confidence=0.5,
16
+ min_tracking_confidence=0.5,
17
+ model_complexity=1)
18
+ self.status_deque = deque(maxlen=1) # Для передачи текста в UI
19
+
20
+ def analyze_posture(self, landmarks, image_shape):
21
+ h, w, _ = image_shape
22
+ left_shoulder = landmarks.landmark[mp_pose.PoseLandmark.LEFT_SHOULDER]
23
+ right_shoulder = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_SHOULDER]
24
+ left_hip = landmarks.landmark[mp_pose.PoseLandmark.LEFT_HIP]
25
+ right_hip = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_HIP]
26
+ left_ear = landmarks.landmark[mp_pose.PoseLandmark.LEFT_EAR]
27
+ right_ear = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_EAR]
28
+ nose = landmarks.landmark[mp_pose.PoseLandmark.NOSE]
29
+
30
+ sitting = left_hip.y < left_shoulder.y + 0.1 or right_hip.y < right_shoulder.y + 0.1
31
+
32
+ messages = []
33
+
34
+ head_forward = (left_ear.y > left_shoulder.y + 0.1 or right_ear.y > right_shoulder.y + 0.1) and \
35
+ (nose.y > left_shoulder.y or nose.y > right_shoulder.y)
36
+ if head_forward:
37
+ messages.append("• Голова наклонена вперед (текстовая шея)")
38
+
39
+ shoulders_rounded = left_shoulder.x > left_hip.x + 0.05 or right_shoulder.x < right_hip.x - 0.05
40
+ if shoulders_rounded:
41
+ messages.append("• Плечи ссутулены (округлены вперед)")
42
+
43
+ shoulder_diff = abs(left_shoulder.y - right_shoulder.y)
44
+ hip_diff = abs(left_hip.y - right_hip.y)
45
+ if shoulder_diff > 0.05 or hip_diff > 0.05:
46
+ messages.append("• Наклон в сторону (несимметричная осанка)")
47
+
48
+ if sitting and (left_hip.y < left_shoulder.y + 0.15 or right_hip.y < right_shoulder.y + 0.15):
49
+ messages.append("• Таз наклонен вперед (сидя)")
50
+
51
+ if messages:
52
+ report = [
53
+ f"**{'Сидя' if sitting else 'Стоя'} - обнаружены проблемы:**",
54
+ *messages,
55
+ "\n**Рекомендации:**",
56
+ "• Держите голову прямо, уши должны быть над плечами",
57
+ "• Отведите плечи назад и вниз",
58
+ "• Держите спину прямой, избегайте наклонов в стороны",
59
+ "• При сидении опирайтесь на седалищные бугры"
60
+ ]
61
+ else:
62
+ report = [
63
+ f"**Отличная осанка ({'сидя' if sitting else 'стоя'})!**",
64
+ "Все ключевые точки находятся в правильном положении.",
65
+ "\n**Совет:**",
66
+ "• Продолжайте следить за осанкой в течение дня"
67
+ ]
68
+
69
+ return "\n\n".join(report)
70
+
71
+ def recv(self, frame: av.VideoFrame) -> av.VideoFrame:
72
+ img = frame.to_ndarray(format="bgr24")
73
+ img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
74
+
75
+ results = self.pose.process(img_rgb)
76
  if results.pose_landmarks:
77
+ # Рисуем ключевые точки
78
  mp_drawing.draw_landmarks(
79
+ img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS,
 
 
80
  mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2),
81
  mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)
82
  )
83
+ status = self.analyze_posture(results.pose_landmarks, img.shape)
84
+ self.status_deque.append(status)
85
  else:
86
+ self.status_deque.append("Ключевые точки не обнаружены")
87
+
88
+ return av.VideoFrame.from_ndarray(img, format="bgr24")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  def main():
91
+ st.set_page_config(layout="wide")
92
+ st.title("📷 Анализатор осанки с веб-камеры (WebRTC)")
93
+ st.write("Приложение анализирует вашу осанку в реальном времени с помощью камеры браузера.")
94
+
95
+ # Запускаем WebRTC стример с нашим процессором
96
+ webrtc_ctx = webrtc_streamer(
97
+ key="pose-analyzer",
98
+ video_processor_factory=PoseProcessor,
99
+ media_stream_constraints={"video": True, "audio": False},
100
+ async_processing=True
101
+ )
102
+
103
+ # Выводим текст анализа из процесса
104
+ if webrtc_ctx.video_processor:
105
+ # Получаем последнюю доступную строку с анализом
106
+ if webrtc_ctx.video_processor.status_deque:
107
+ analysis_text = webrtc_ctx.video_processor.status_deque[-1]
108
+ else:
109
+ analysis_text = "Ожидание видео и анализа..."
110
+
111
+ st.markdown("### Анализ осанки:")
112
+ st.markdown(analysis_text)
 
 
113
 
114
  if __name__ == "__main__":
115
  main()