项目概述
- 目的:构建一个身体姿势检测系统,能够从视频中识别出正确的侧视图,并测量颈部和躯干相对于参考轴的倾斜角度。
- 关键功能:
- 检测并分析人体姿势。
- 计算特定姿势持续的时间。
- 确保摄像头对准正确的侧视图。
- 当不良姿势超过设定阈值时发送警报。
计算身体姿势倾斜度的功能
角度是姿势的主要决定因素。我们使用领口和躯干线到 y 轴的角度。领口连接肩膀和眼睛。在这里,我们以肩膀为关键点。
同样,躯干线连接臀部和肩膀,臀部被认为是一个关键点。
计算偏移距离的功能
该设置要求该人处于正确的侧视图中。函数 findDistance 帮助我们确定两点之间的偏移距离。它可以是臀部、眼睛或肩膀。
之所以选择这些点,是因为它们总是或多或少地围绕人体的中心轴线对称。有了这个,我们将在脚本中加入相机对齐功能。
技术栈
- 主要库:OpenCV, MediaPipe
- 安装依赖:
pip install -r requirements.txt
工作流程
- 初始化:设置常量、颜色、字体样式等,并初始化MediaPipe Pose类。
- 读取视频帧:创建VideoCapture对象来读取输入视频,同时创建VideoWriter对象以保存输出视频。
- 处理每一帧:
- 将BGR图像转换为RGB,因为MediaPipe需要RGB格式。
- 使用MediaPipe处理图像,获取姿态地标。
- 转换回BGR格式以进行后续的OpenCV操作。
- 计算坐标:根据MediaPipe返回的数据,计算实际的身体部位坐标。
- 相机对齐检查:通过比较左右肩膀之间的距离来判断是否正确对齐。
- 姿势分析:计算颈部和躯干的倾斜角度,评估姿势好坏,并在图像上绘制相关结果。
- 时间追踪:记录保持良好或不良姿势的时间。
- 警报机制:当不良姿势时间超过一定阈值时触发警报。
关键代码段
findDistance(x1, y1, x2, y2)
: 计算两点之间的欧氏距离。findAngle(x1, y1, x2, y2)
: 计算两向量间的夹角。sendWarning()
: 定义发送警报的行为(可自定义)。
# Determine whether good posture or bad posture.
# The threshold angles have been set based on intuition.
if neck_inclination < 40 and torso_inclination < 10:
bad_frames = 0
good_frames += 1
cv2.putText(image, angle_text_string, (10, 30), font, 0.9, light_green, 2)
cv2.putText(image, str(int(neck_inclination)), (l_shldr_x + 10, l_shldr_y), font, 0.9, light_green, 2)
cv2.putText(image, str(int(torso_inclination)), (l_hip_x + 10, l_hip_y), font, 0.9, light_green, 2)
# Join landmarks.
cv2.line(image, (l_shldr_x, l_shldr_y), (l_ear_x, l_ear_y), green, 4)
cv2.line(image, (l_shldr_x, l_shldr_y), (l_shldr_x, l_shldr_y - 100), green, 4)
cv2.line(image, (l_hip_x, l_hip_y), (l_shldr_x, l_shldr_y), green, 4)
cv2.line(image, (l_hip_x, l_hip_y), (l_hip_x, l_hip_y - 100), green, 4)
else:
good_frames = 0
bad_frames += 1
cv2.putText(image, angle_text_string, (10, 30), font, 0.9, red, 2)
cv2.putText(image, str(int(neck_inclination)), (l_shldr_x + 10, l_shldr_y), font, 0.9, red, 2)
cv2.putText(image, str(int(torso_inclination)), (l_hip_x + 10, l_hip_y), font, 0.9, red, 2)
# Join landmarks.
cv2.line(image, (l_shldr_x, l_shldr_y), (l_ear_x, l_ear_y), red, 4)
cv2.line(image, (l_shldr_x, l_shldr_y), (l_shldr_x, l_shldr_y - 100), red, 4)
cv2.line(image, (l_hip_x, l_hip_y), (l_shldr_x, l_shldr_y), red, 4)
cv2.line(image, (l_hip_x, l_hip_y), (l_hip_x, l_hip_y - 100), red, 4)
# Calculate the time of remaining in a particular posture.
good_time = (1 / fps) * good_frames
bad_time = (1 / fps) * bad_frames
# Pose time.
if good_time > 0:
time_string_good = 'Good Posture Time : ' + str(round(good_time, 1)) + 's'
cv2.putText(image, time_string_good, (10, h - 20), font, 0.9, green, 2)
else:
time_string_bad = 'Bad Posture Time : ' + str(round(bad_time, 1)) + 's'
cv2.putText(image, time_string_bad, (10, h - 20), font, 0.9, red, 2)
# If you stay in bad posture for more than 3 minutes (180s) send an alert.
if bad_time > 180:
sendWarning()
注意事项
- 角度和偏移阈值是基于经验设定的,可以根据实际情况调整。
- 为了确保准确的姿势检测,必须保证摄像头拍摄到的是人的侧面视角。
- 可以根据需要扩展
sendWarning()
函数的功能,比如集成外部通知服务。
此文档提供了构建一个基本姿势校正应用程序所需的所有步骤。您可以根据上述指导开始编写代码,并且可以根据个人需求进一步优化和完善该系统。