File size: 5,464 Bytes
1c04e5a 278392e 63de751 2ba6916 278392e 2ba6916 1c04e5a 2ba6916 63de751 1c04e5a 2ba6916 8535b44 2ba6916 8535b44 2ba6916 8535b44 2ba6916 8535b44 2ba6916 1c04e5a 63de751 2ba6916 1c04e5a 63de751 |
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 |
import streamlit as st
import cv2
import numpy as np
from streamlit_webrtc import webrtc_streamer, VideoProcessorBase
import mediapipe as mp
import av
from collections import deque
# Инициализация MediaPipe Pose
mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils
class PoseProcessor(VideoProcessorBase):
def __init__(self):
self.pose = mp_pose.Pose(min_detection_confidence=0.5,
min_tracking_confidence=0.5,
model_complexity=1)
self.status_deque = deque(maxlen=1) # Для передачи текста в UI
def analyze_posture(self, landmarks, image_shape):
h, w, _ = image_shape
left_shoulder = landmarks.landmark[mp_pose.PoseLandmark.LEFT_SHOULDER]
right_shoulder = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_SHOULDER]
left_hip = landmarks.landmark[mp_pose.PoseLandmark.LEFT_HIP]
right_hip = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_HIP]
left_ear = landmarks.landmark[mp_pose.PoseLandmark.LEFT_EAR]
right_ear = landmarks.landmark[mp_pose.PoseLandmark.RIGHT_EAR]
nose = landmarks.landmark[mp_pose.PoseLandmark.NOSE]
sitting = left_hip.y < left_shoulder.y + 0.1 or right_hip.y < right_shoulder.y + 0.1
messages = []
head_forward = (left_ear.y > left_shoulder.y + 0.1 or right_ear.y > right_shoulder.y + 0.1) and \
(nose.y > left_shoulder.y or nose.y > right_shoulder.y)
if head_forward:
messages.append("• Голова наклонена вперед (текстовая шея)")
shoulders_rounded = left_shoulder.x > left_hip.x + 0.05 or right_shoulder.x < right_hip.x - 0.05
if shoulders_rounded:
messages.append("• Плечи ссутулены (округлены вперед)")
shoulder_diff = abs(left_shoulder.y - right_shoulder.y)
hip_diff = abs(left_hip.y - right_hip.y)
if shoulder_diff > 0.05 or hip_diff > 0.05:
messages.append("• Наклон в сторону (несимметричная осанка)")
if sitting and (left_hip.y < left_shoulder.y + 0.15 or right_hip.y < right_shoulder.y + 0.15):
messages.append("• Таз наклонен вперед (сидя)")
if messages:
report = [
f"**{'Сидя' if sitting else 'Стоя'} - обнаружены проблемы:**",
*messages,
"\n**Рекомендации:**",
"• Держите голову прямо, уши должны быть над плечами",
"• Отведите плечи назад и вниз",
"• Держите спину прямой, избегайте наклонов в стороны",
"• При сидении опирайтесь на седалищные бугры"
]
else:
report = [
f"**Отличная осанка ({'сидя' if sitting else 'стоя'})!**",
"Все ключевые точки находятся в правильном положении.",
"\n**Совет:**",
"• Продолжайте следить за осанкой в течение дня"
]
return "\n\n".join(report)
def recv(self, frame: av.VideoFrame) -> av.VideoFrame:
img = frame.to_ndarray(format="bgr24")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
results = self.pose.process(img_rgb)
if results.pose_landmarks:
# Рисуем ключевые точки
mp_drawing.draw_landmarks(
img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS,
mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2),
mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2)
)
status = self.analyze_posture(results.pose_landmarks, img.shape)
self.status_deque.append(status)
else:
self.status_deque.append("Ключевые точки не обнаружены")
return av.VideoFrame.from_ndarray(img, format="bgr24")
def main():
st.set_page_config(layout="wide")
st.title("📷 Анализатор осанки с веб-камеры (WebRTC)")
st.write("Приложение анализирует вашу осанку в реальном времени с помощью камеры браузера.")
# Запускаем WebRTC стример с нашим процессором
webrtc_ctx = webrtc_streamer(
key="pose-analyzer",
video_processor_factory=PoseProcessor,
media_stream_constraints={"video": True, "audio": False},
async_processing=True
)
# Выводим текст анализа из процесса
if webrtc_ctx.video_processor:
# Получаем последнюю доступную строку с анализом
if webrtc_ctx.video_processor.status_deque:
analysis_text = webrtc_ctx.video_processor.status_deque[-1]
else:
analysis_text = "Ожидание видео и анализа..."
st.markdown("### Анализ осанки:")
st.markdown(analysis_text)
if __name__ == "__main__":
main() |