# FMS-python **Repository Path**: njcky/fms-python ## Basic Information - **Project Name**: FMS-python - **Description**: FMS functional movement screen 功能性动作筛查python版 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-11-24 - **Last Updated**: 2023-07-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 流程 0. 激活环境 > conda activate open-mmlab > pip install onnxruntime-gpu==1.6.0 > CUDA 10.2 & cudnn8 1. 文件夹下只有mkv类型视频,0代表正面,1代表右面,2代表左面 1.0 执行完整流程: > python main.py 1.1 耗时操作:`mkv`文件全部转码为`avi`文件; 依次读取`avi`文件, 并同路径下生成同名`json`文件(全身关节点坐标) 1.2 动作判断操作: 若无`avi`会生成`avi`, 若无`json`会生成`json`, 若都存在,依次判断7个动作 1.2.1 读取`全身关节点坐标.json`, 同路径下生成`精简后的关节点.json` 1.2.2 读取`精简后的关节点.json`, 执行判断打分, 同路径下生成`视频绘制内容.json` 1.2.3 同时读取3个 `视频.avi`, `精简后的关节点.json`, `视频绘制内容.json` 并逐帧绘制,得到最终结果 `demo.avi` 位于同路径下 2. 文件下已经存在 `1.1` “耗时操作”生成的 `视频同名.avi` `视频同名.json` 2.1 删除 `1.2` 中生成的所有文件 > python clear_checker.py 2.2 执行动作判断, 生成`demo.avi`, 同 `1.2` 3. 工具 删除 `1.1` `1.2` 生成的结果, 恢复初始状态 > python clear_all.py 删除 `1.2` 生成的记过,恢复未经动作判断的状态 > python clear_checker.py 4. 文件功能 4.1`VideoConvertor.py` 视频转换工具:`mkv`转`avi`;`avi`转`关键点.json`;路径文件遍历;路径文件清理; 4.2 `MyJoints.py` 关节点处理工具:关节点,骨骼 坐标重索引,精简,存储`my_方位_joints.json`~~主体人物判断,视角判断~~ 4.3 `Checker.py` 动作判断工具:向量,角度计算,动作打分——输入`my_方位_joints.json`,输出`my_方位_joints_hints.json` 4.4 `VisualRGB.py` 可视化工具:关节,骨骼上色,提示信息绘制——输入`.avi`x3 `my_方位_joints.json`x3, `my_方位_joints_hints.json`x3,输出视频合成结果 `demo.avi` # 深蹲 1. 躯干垂直:正面躯干垂直角度小于10°,且两侧躯干垂直角度小于20°;三面共同时间占比 > 0.8 为标准 2. 大腿低于水平面:双大腿能够同时低于水平面;存在即为标准 3. 双膝双足平行:膝足角度小于5°即为平行;平行时间占比 > 0.6 为标准 4. 横杆是否平行:腕踝角度小于10°即为平行;平行时间占比 > 0.6 为标准 5. 是否存在脚离开地面:双侧,脚跟与地面距离大于50个像素;存在即不得满分 ```python ''' 判断得分的门限参数 ''' torso_vertical_ratio_threshold = 0.8 # 躯干垂直时间占比门限 knees_foots_parallel_ratio_threshold = 0.6 # 膝足平行时间占比门限 wrists_parallel_ratio_threshold = 0.6 # 横杆平行时间占比门限 ''' 判断动作标准的门限参数 ''' torso_angle_threshold_f = 10 # 正面躯干角度门限 torso_angle_threshold_rl = 20 # 侧面躯干角度门限 knees_foots_angle_threshold = 5 # 双膝双足夹角门限 wrists_angle_threshold = 10 # 横杆夹角门限 footend_y_offset_threshold = 50 # 脚跟离地像素门限 ``` 预定义5种条件,第5个条件具有不得满分的一票否决权 条件1:全部3视角 躯干同时垂直时间占比,是否超过门限 条件2:侧面2视角 同时出现大腿低于水平面,是否存在 条件3:正面1视角 膝足不平行时间占比,是否超过门限 条件4:正面1视角 横杆不平行时间占比,是否超过门限 条件5:侧面2视角 双脚是否离地,是否存在 不得满分(3分):需要挑选帧可视化 **2分对应情况:** 1. 条件1-4有一个不满足:先查询条件,再查询不满足的视角,最后查询不满足条件的帧们 `233` 代表异常帧序号 存储图片命名为:`*_for_cond1_233.jpg` 存储图片命名为:`*_for_cond2_233.jpg` 存储图片命名为:`*_for_cond3_233.jpg` 存储图片命名为:`*_for_cond4_233.jpg` 其中 `cond2` 存储的是条件符合的帧,表示标准姿势,其他的condition都存储的是条件不符合的帧 2. 条件1-4全满足,但是条件5不满足(json中字段 is_over_ground 判断) 存储图片命名为:`*_for_cond5_233.jpg` **1分对应情况:** 1. 条件5不满足,且条件1-4有一个不满足 存储图片命名为:`*_for_cond1_233.jpg` 存储图片命名为:`*_for_cond2_233.jpg` 存储图片命名为:`*_for_cond3_233.jpg` 存储图片命名为:`*_for_cond4_233.jpg` 存储图片命名为:`*_for_cond5_233.jpg` # 跨栏架步 1. 臀,膝,脚踝 在同一平面内: 仅在**运动时间内**判定,仅**判定前脚** 3个关节点在正面垂直角度都小于30°,判定3点处于同一矢状面; 3关节都处于同一矢状面内时间占**总运动时间**比例 > 0.5 为标准 2. 腰部没明显晃动: 2.0 首先满足:三面躯干两端点与初始时水平偏移小于30像素 2.1 站立时:正面躯干垂直角度小于5°,侧面躯干垂直角度小于10°; 2.2 抬腿时:脚跟离开地面20个像素即判定为抬腿,正面躯干垂直角度小于5°,侧面躯干垂直角度小于30°; 腰部稳定时间占比 > 0.5 为标准 3. 横杆保持水平: 腕踝角度小于10°即为平行; 平行时间占比 > 0.6 为标准 4. 身体是否失去平衡:3面存在1面的躯干垂直角度大于45°;存在即得1分 ```python ''' 判断得分的门限参数 ''' legs_in_plane_threshold = 0.5 # 标准1 臀,膝,脚踝 在同一矢状面时间占比门限 lumbar_stable_threshold = 0.5 # 标准2 腰部稳定时间占比门限 wrists_parallel_ratio_threshold = 0.5 # 标准3 木棒平行时间占比门限 ''' 判断动作标准的门限参数 ''' plane_angle_threshold = 30 # 矢状面角度门限 footend_y_offset_threshold = 20 # 脚跟离地像素门限 torso_x_offset_threshold = 30 # 腰椎水平偏移像素门限 wrists_angle_threshold_f = 10 # 正面木棒平行角度门限 torso_angle_balance_threshold = 45 # 正面躯干平衡角度门限 ``` 预定义4种条件,第4个条件具有不得满分的一票否决权 条件1:臀膝踝位于矢状面内的时间占比,超过门限值(运动期间:正面腿部4根线的垂直角度均小于角度门限的帧比例) 条件2:腰部稳定时间占比,超过门限值(运动期间:3面存在水平偏移过远,则不稳定) 条件3:横杆平行时间占比,超过门限值 条件4:是否失去平衡 **2分对应情况:** 没有失去平衡 and 条件1-3有一个不满足 cond1: 对应 `*_for_cond1_233.jpg` 最多不超过2张图,区分右半身和左半身 cond2: 对应 `*_for_cond2_233.jpg` 最多不超过6张图,区分弓步状态,非弓步状态, 3视角 cond3: 对应 `*_for_cond1_233.jpg` 最多不超过1张图 **1分对应情况:** 失去平衡:3视角 存在躯干倾角过大,可视化出问题的视角 `front_lose_balance_233.jpg` `right_lose_balance_233.jpg` `left_lose_balance_233.jpg` # 直线弓箭步 ## ~~深度信息(3d坐标系下)~~ ~~所有动作需要去除冗余动作,保留左右弓步时刻动作;~~ - ~~右弓步时刻:举左手,正面左手肘关节高于左肩 && 右腿弯曲角度 < 120 °时候~~ - ~~左弓步时刻:举右手,正面右手肘关节高于右肩 && 左腿弯曲角度 < 120 °时候~~ 1. ~~横杆保持三处接触。~~ ~~1.1 右侧:右手腕关节 与 腰椎 x坐标距离 < 20cm; && 左手腕关节 与 脖子 x坐标距离 < 20cm;~~ ~~右弓步符合标准时间:t1~~ ~~1.2:左弓步同理;t2~~ ~~横杆保持三处接触总时间:t1∪t2,判断时间占比~~ 2. ~~横杆保持与地面垂直。侧面腕关节难以识别,因此以以躯干近似横杆。~~ ~~2.1:右侧:右手腕关节(lower) - 左手腕关节 垂直角度 < 5°;时间t3~~ ~~2.2:左侧:左手腕关节(lower) - 右手腕关节 垂直角度 < 5°;时间t4~~ ~~横杆保持垂直总时间:t3∪t4;时间占总弓步时间比 > 0.5,该标准合格。记1分。~~ 3. ~~躯干保持稳定。~~ ~~右弓步正面垂直角度 < 30, 时间t5~~ ~~左弓步正面垂直角度 < 30, 时间t6~~ ~~t5∪t6,判断时间占比~~ 4. ~~横杆与两足始终处于矢状面内。~~ ~~4.1:右弓步右视图:观察深度z坐标;右手腕 - 左手腕 < 5cm; 右手腕 - 右脚 < 5cm;右脚 - 左脚 < 5cm;t7~~ ~~4.2:左弓步左视图:观察深度z坐标;右手腕 - 左手腕 < 5cm; 右手腕 - 右脚 < 5cm;右脚 - 左脚 < 5cm;t8~~ ~~t7∪t8 判断时间占比~~ 5. ~~后膝能够触及前足跟~~ ~~5.1 右弓步右视图:观察x坐标,左膝关节 - 右踝关节 < 10cm。t9~~ ~~5.2 左弓步左视图:观察x坐标,右膝关节 - 左踝关节 < 10cm。t10~~ ~~t9∪t10,判断时间占比~~ ## 2d坐标系 1. 竖杆保持3处接触 侧面视角手部遮挡过多,手部关节位置预测不准 手腕贴近后背是较容易做到的,整个视频中,存在贴紧的时刻,该标准得分 - 右弓步时判断贴紧 (左右视图其一满足即可) 右视图:"脖子 & 右手尖" x坐标差距小于30像素 and "盆骨 & 左手尖" x坐标差距小于30像素 flag1 左视图:"脖子 & 右手尖" x坐标差距小于30像素 and "盆骨 & 左手尖" x坐标差距小于30像素 flag2 FLAG_RIGHT = flag1 or flag2 - 左弓步时判断贴紧 (左右视图其一满足即可) 右视图:"脖子 & 左手尖" x坐标差距小于30像素 and "盆骨 & 右手尖" x坐标差距小于30像素 flag3 左视图:"脖子 & 左手尖" x坐标差距小于30像素 and "盆骨 & 右手尖" x坐标差距小于30像素 flag4 FLAG_LEFT = flag3 or flag4 FALG_RIGHT == True or FLAG_LEFT == True 该标准得分 2. 横杆保持与地面垂直(f,r,l) 正面关节准,可以算时间占比(主要判断) 侧面关节乱,存在过大角度则一票否决(辅助判断,具有一票否决权); 侧面实际操作难度大: 人眼难以看到关节; 算法没训练过这种奇怪姿势。 => 躯干与竖杆近似平行,躯干角度代替竖杆角度; 缺陷:由于正面关节的遮挡:正面我手扭一个诡异的角度,导致竖杆歪七扭八,是无法通过人体关键点检测到竖杆是否垂直的 主视角:躯干垂直角度 < 10 左右视角:躯干垂直角度 < 30 计算时间占比 > 0.7,该标准得分 3. 躯干保持稳定(f,l,r) 同上 4. 横杆与双足始终处于矢状面内(f) - 右弓步:左手-右手与垂直夹角A1,右手-右踝与垂直夹角A2 A1 < 10 and A2 < 10 ; T1++ - 左弓步:右手-左手与垂直夹角A3,左手-左踝与垂直夹角A4 A3 < 10 and A4 < 10 ; T2++ T4_RATIO = (T1 + T2) / 运动总时间 计算时间占比 > 0.5,该标准得分 5. 后脚接触前脚跟 - 右弓步,右视角,右脚跟,左膝盖 x坐标差值 < 50像素 - 左弓步,左视角,左脚跟,右膝盖 x坐标差值 < 50像素 左右都存在,该标准得分 6. 是否失去平衡 - 主视角:躯干垂直角度 > 45 flag5 - 右视角:躯干垂直角度 > 45 flag6 - 左视角:躯干垂直角度 > 45 flag7 FLAG_BALANCE = flag5 or flag6 or flag7 FLAG_BALANCE == True,不得满分 ```python ''' 判断得分的门限参数 ''' torso_vertical_ratio_threshold = 0.8 # 躯干垂直/竖杆垂直时间占比门限 dowel_in_plane_ratio_threshold = 0.5 # 横杆和足部在同一矢状面时间占比门限 ''' 判断动作标准的门限参数 ''' angle_leg_threshold = 120 # 腿部弯曲角度门限(弓步是否开始) neck_hand_x_gap_threshold = 30 # 侧面脖子手尖横坐标差值门限 pelvis_hand_x_gap_threshold = 30 # 侧面盆骨手尖横坐标差值门限 angle_torso_threshold_f = 10 # 正面躯干垂直角度门限 angle_torso_threshold_rl = 20 # 侧面躯干垂直角度门限 angle_dowel_in_plane_threshold = 10 # 正面横杆与双足角度门限 knee_footend_x_offset_threshold = 50 # 侧面膝盖和足跟距离门限 angle_torso_balance_threshold = 45 # 正侧面躯干平衡角度门限 ``` 1 横杆是否存在三处接触 2 横杆保持与地面垂直时间占比 3 躯干保持稳定时间占比 4 横杆与双足始终处于矢状面内时间占比 5 左弓步和右弓步后脚都能接触前脚跟 6 是否失去平衡 预定义6个条件 **1分对应情况:** 失去平衡:3视角 存在躯干倾角过大,可视化出问题的视角 `front_lose_balance_233.jpg` `right_lose_balance_233.jpg` `left_lose_balance_233.jpg` **2分对应情况:** 没有失去平衡 and 条件1-5有一个不满足 cond1: 对应 `*_for_cond1_233.jpg` 最多不超过4张图,区分右侧运动和左侧运动, 2视角 cond2: 对应 `*_for_cond2_233.jpg` 最多不超过3张图,3视角 cond3: 对应 `*_for_cond3_233.jpg` 最多不超过3张图,3视角 cond4: 对应 `*_for_cond4_233.jpg` 最多不超过2张图,区分右侧运动和左侧运动,正面 cond5: 对应 `*_for_cond5_233.jpg` 最多不超过2张图,区分右侧运动和左侧运动,侧面 # 肩部灵活性 掌长 = 2/3 头长 = 2/3 前臂长 拳距离 = 大拇指距离 右:右手高于左手,左手高于左肘 左:左手高于右手,右手高于右肘 1. 判断背面视角的两拳距离 存在两拳距离小于1掌长:3分 存在两拳距离小于1.5掌长:2分 存在两拳距离大于1.5掌长:1分 ```python is_move_right_less_1_hand_length = False is_move_right_less_1dot5_hand_length = False is_move_right_higher_1dot5_hand_length = False is_move_left_less_1_hand_length = False is_move_left_less_1dot5_hand_length = False is_move_left_higher_1dot5_hand_length = False ``` 这个动作不存在异常帧 可视化正常帧 cond1:对应3分;如果3分,可视化:`less_1_hand_for_cond1_233.jpg` cond2:对应2分;如果2分,可视化:`less_1dot5_hand_for_cond2_233.jpg` cond3:对应1分;如果1分,可视化:`higher_1dot5_hand_for_cond3_233.jpg` # 主动直膝抬腿 抬腿判断:两踝关节y坐标差值大于50像素 1. 判断左面:腿踝骨垂线落在大腿中部和髂前上棘之间:3分 2. 判断左面:腿踝骨垂线落在大腿中部和膝关节之间:2分 3. 判断左面:腿踝骨垂线落在膝关节以外:1分 ```python """ 门限 """ ankle_y_gap_threshold = 50 # 踝关节y坐标差值门限(判断左抬腿or右抬腿 ``` 这个动作不存在异常帧 可视化正常帧 cond1:对应3分;如果3分,可视化, 不超过2张图:`left_R_for_cond1_233.jpg` `left_L_for_cond1_233.jpg` cond2:对应2分;如果2分,可视化, 不超过2张图:`left_R_for_cond2_233.jpg` `left_L_for_cond2_233.jpg` cond3:对应1分;如果1分,可视化, 不超过2张图:`left_R_for_cond3_233.jpg` `left_L_for_cond3_233.jpg` # 躯干稳定性俯卧撑 头长:前臂长 前额:脖子纵向偏移1个头长 下颌:脖子纵向偏移0.5个头长 俯卧撑判定:正面脖子离开地面20像素 D1 if !D1: 正面:大拇指与前额(下颌,肩部)y坐标看距离谁最近 距离前额最近: 距离下颌最近: 距离肩部最近: if D1: 判断躯干滞后程度:存在170以内的角度即失败 不管男女,能与前额平行就3分, 且不存在躯干滞后 男性靠近下颌 or 存在躯干晃动,2分, 女性靠近下颌且不晃动,3分,靠近下颌且晃动,2分 男性靠近肩膀 or 存在躯干晃动,1分, 女性靠近肩膀且不晃动,2分,靠近肩膀且晃动,1分 ```python """ 打分门限参数 """ is_near_forehead_history = False is_near_chin_history = False is_near_shoulder_history = False is_torso_lag_history = False """ 动作判断门限参数 """ neck_y_gap_f_threshold = 20 # 脖子离开地面门限 pelvis_x_gap_f_threshold = 20 # 正面盆骨左右晃动门限 neck_x_gap_f_threshold = 20 # 正面脖子左右晃动门限 # thumb_forehead_y_gap_threshold = 20 # 拇指前额水平距离门限 # thumb_chin_y_gap_threshold = 20 # 拇指下颌水平距离门限 # thumb_shoulder_y_gap_threshold = 20 # 拇指肩膀水平距离门限 forehead_ratio = 1.2 # 头部关键点位置系数 chin_ratio = 1 # 头部关键点位置系数 ``` 预定义4种情况 cond1 双手和前额在一条线 cond2 双手和下巴在一条线 cond3 双手和锁骨在一条线 cond4 ~~盆骨是否离开地面~~ -> 躯干滞后性; **2分对应情况:** 男生: 无滞后,cond1 x, cond2 ✔, cond3 x `2fen_front_for_cond2_233.jpg` 女生: 无滞后,cond1 x, cond2 x, cond3 ✔ `2fen_front_for_cond3_233.jpg` **1分对应情况:** 有滞后: `1fen_left_for_cond4_233.jpg` 男生: 不满足cond1,cond2,满足cond3,满足cond4:可视化cond3 `*1_fen_man_for_cond3_233.jpg` 女生: 不满足cond1,cond2,满足cond3,不满足cond4:可视化cond3,cond4 `*1_fen_woman_for_cond3_233.jpg` `*1_fen_woman_for_cond4_233.jpg` # 躯干旋转稳定性 分割同侧上下肢运动,异侧上下肢运动 同侧上下肢(D1): 右同侧运动(D1_r):右手(右面)抬起,右膝盖(右面)离地20像素 左同侧运动(D1_l):左手(左面)抬起,左膝盖(左面)离地20像素 异侧上下肢(D2): 右异侧运动(D2_r):右手(右面)抬起,右膝(右面)距离地面20像素以内,且左膝盖离地20像素(左面) 左异侧运动(D2_l):左手(左面)抬起,左膝(左面)距离地面20像素以内,且右膝盖离地20像素(右面) 水平角度门限:20 D1时: T1++ D1_r 时,躯干水平(右侧)t1 ++ D1_l 时,躯干水平(左侧)t2 ++ 时间占比 (t1+t2)/T1 D2时: T2++ D2_r 时,躯干水平(右侧)t3 ++ D2_l 时,躯干水平(左侧)t4 ++ 时间占比 (t3+t4)/T2 If D1: 时间占比 > 0.8 3分 If D2 时间占比 > 0.8 2分 if not D1 and not D2 1分 ```python ''' 判断得分的门限参数 ''' torso_horizontal_ratio_threshold = 0.8 ''' 判断动作标准的门限参数 ''' is_over_ground_threshold = 20 # 离地面高度门限 angle_torso_r_threshold = 20 # 躯干角度门限 ``` cond1 躯干平行时间占比 cond2 是否同侧运动 cond3 是否异侧运动 文件名中: S代表同侧运动 D代表异侧运动 **2分对应情况:** 满足cond1,cond2,不满足cond3:可视化cond2(同侧运动) `rotary_stability_2_fen_S_for_cond2_233.jpg` 满足cond3,不满足cond1,不满足cond2:可视化cond2,cond1(异侧运动) `rotary_stability_2_fen_D_for_cond2_233.jpg` `rotary_stability_2_fen_D_for_cond1_233.jpg` **1分对应情况:** 满足cond3,不满足cond2,不满足cond1,可视化cond1(异侧运动) `rotary_stability_1_fen_D_for_cond1_233.jpg`