一、环境安装
1、根据电脑配置选择安装pytorch。
pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu113
pytorch官网或者pytorch 的whl稳定版本下载安装。
2、安装ultraytics
pip install ultralytics -i https://pypi.mirrors.ustc.edu.cn/simple/
3、三方库安装
pip install -r requirements.txt
二、目标检测和姿态估计
1、目标检测模型,典型代表有YOLO、SSD和Yolo等。这些方法采用基于回归的思想,在输入图像的多个位置直接回归出区域框坐标和物体类别,具有快速的识别速度和与faster R-CNN相当的准确率。本实例项目基与yolov8n-pose预训练模型实现人的站立、跌倒、坐的姿 态估计。
2、下载模型存放weights文件夹下。
3、导入三方库
from PIL import Image
from ultralytics import YOLO
import cv2
import cvzone
from Class.decision import *
import argparse
4、主程序
def run(source = None,
required=True
):
# 加载权重
model = YOLO(dec.WEIGHT)
# 定义图像文件的路径
if required:
_source = f'fallimage/{source}'
else:
_source = f'fallimage/fall15.png'
results = model(_source) # Results 对象列表
# 获取xyxy格式的边界框信息
boxes = results[0].boxes.xyxy.cpu().numpy().astype(int)
statuses = []
# 获取所有被检测对象的关键点数据
keypoints_data = results[0].keypoints.data
# 遍历被检测的对象
for i, keypoints in enumerate(keypoints_data):
# 确保检测到关键点
if keypoints.shape[0] > 0:
status_score = dec.is_fallen(keypoints,boxes[i])
print(f"Person {i + 1} has {status_score}.")
statuses.append(f'boxID:{i} {status_score}')
#绘制识别框以及标签
im_array = results[0].plot() # 绘制包含预测结果的BGR numpy数组
for i in range(len(boxes)):
x1, y1, x2, y2 = boxes[i]
#绘制识别框
#cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
#绘制姿态标签
cvzone.putTextRect(
im_array, f"{statuses[i]}", (x1+8, y2 - 8),
scale=0.8, thickness=0,
colorT=(255, 255, 255), colorR=(255, 0, 255),
font=cv2.FONT_HERSHEY_COMPLEX,
)
im = Image.fromarray(im_array[..., ::-1])
im.show() # 显示图像
if required:
save_name=source.split('.')
im.save(f'runs/pose/{save_name[0]}_1.{save_name[1]}') # 保存图像
def parse_opt():
"""Parse command line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument('--source', type=str, required=True, help='video file path')
return parser.parse_args()
def main(opt):
"""Main function."""
run(**vars(opt))
if __name__ == '__main__':
opt = parse_opt()
main(opt)
5、姿态估计核心算法
def is_fallen(self,keypoints,boxes):
Left_Shoulder = keypoints[5][:2]
if Left_Shoulder[0] + Left_Shoulder[1] == 0: self.ATHERPOSE += 1
Right_Shoulder = keypoints[6][:2]
if Right_Shoulder[0] + Right_Shoulder[1] == 0: self.ATHERPOSE += 1
Left_Hip = keypoints[11][:2]
if Left_Hip[0] + Left_Hip[1] == 0: self.ATHERPOSE += 1
Right_Hip = keypoints[12][:2]
if Right_Hip[0] + Right_Hip[1] == 0: self.ATHERPOSE += 1
Left_Knee = keypoints[13][:2]
if Left_Knee[0] + Left_Knee[1] == 0: self.ATHERPOSE += 1
Right_Knee = keypoints[15][:2]
if Right_Knee[0] + Right_Knee[1] == 0: self.ATHERPOSE += 1
Left_Ankle = keypoints[15][:2]
if Left_Ankle[0] + Left_Ankle[1] == 0: self.ATHERPOSE += 1
Right_Ankle = keypoints[16][:2]
if Right_Ankle[0] + Right_Ankle[1] == 0: self.ATHERPOSE += 1
Shoulders_c = [(Left_Shoulder[0]+Right_Shoulder[0]) // 2,
(Left_Shoulder[1]+Right_Shoulder[1]) // 2]
hips_c = [(Left_Hip[0]+Right_Hip[0]) // 2,
(Left_Hip[1]+Right_Hip[1]) // 2]
Knee_c = [(Left_Knee[0]+Right_Knee[0]) // 2,
(Left_Knee[1]+Right_Knee[1]) // 2]
Ankle_c = [(Left_Ankle[0] + Right_Ankle[0]) // 2,
(Left_Ankle[1] + Right_Ankle[1]) // 2]
'''计算身体中心线与水平线夹角'''
human_angle = self.getAnglebyline([Shoulders_c,hips_c],[[0, 0], [10, 0]])
'''计算检测区域宽高比'''
aspect_ratio = self.aspectRatio(boxes)
'''计算肩部中心点与胯部中心点的垂直距离差'''
human_shoulderhip = abs(Shoulders_c[1]-hips_c[1])
'''计算肩部胯部膝盖夹角'''
Hip_Knee_Shoulders_angle = self.getAnglebypoint(Shoulders_c,hips_c,Knee_c)
Hip_Knee_Right_angle = self.getAnglebypoint(Right_Shoulder.tolist(),Right_Hip.tolist(),Right_Knee.tolist())
'''计算胯部膝盖小腿夹角'''
Ankle_Knee_Hip_angle = self.getAnglebypoint(hips_c,Knee_c,Ankle_c)
Ankle_Knee_Right_angle = self.getAnglebypoint(Right_Hip.tolist(), Right_Knee.tolist(), Right_Ankle.tolist())
'''计算胯部膝盖是否处于相似的垂直位置'''
vertical_threshold = Left_Knee[1] - Left_Shoulder[1]
'''计算胯部膝盖是否处于相似的水平位置'''
horizontal_threshold = Left_Shoulder[0] - Left_Knee[0]
status_score = {'Stand': 0.0,
'Fall': 0.0,
'Sit': 0.0,
'other':0.0}
_weight=''
if self.ATHERPOSE>=8: status_score['other'] += 5.6
'''判断Shoulder、Hip、Knee是否被检测到'''
if Knee_c[0]== 0 and Knee_c[1]== 0 and hips_c[0]==0 and hips_c[1] == 0:
status_score['Sit'] += 0.69
status_score['Fall'] += -0.8*2
status_score['Stand'] += -0.8*2
_weight = f'[1]Sit:+0.2, Fall:-1.6 ,Stand: -1.6'
elif Shoulders_c[1] == 0 and Shoulders_c[0] == 0 and hips_c[0]==0 and hips_c[1] == 0:
status_score['Sit'] += -0.8 * 2
status_score['Fall'] += -0.8 * 2
status_score['Stand'] += 0.69
else:
if 180>Ankle_Knee_Hip_angle[1]>125 and aspect_ratio[0] < self.ASPECT_RATIO:
status_score['Stand'] += 1.6
if 25>Ankle_Knee_Hip_angle[1]>-25 and aspect_ratio[0] > 1 / self.ASPECT_RATIO:
status_score['Fall'] += 1.6
if 125 > Ankle_Knee_Hip_angle[1] > 75:
status_score['Sit'] += 0.6
_weight = f'[1]Sit:+0.2, Fall:-1.6 ,Stand: -1.6'
'''身体中心线与水平线夹角+-25'''
if human_angle in range(-self.HUMAN_ANGLE, self.HUMAN_ANGLE):
status_score['Fall'] += 0.8
status_score['Sit'] += 0.1
_weight=f'{_weight}, [2]Fall:+0.8, Sit:+0.1'
else:
status_score['Fall'] += 0.2*((90-human_angle)/90)
_weight = f'{_weight}, [3]Fall:+{0.8*((90-human_angle)/90)}'
'''宽高比小与0.6则为站立'''
if (aspect_ratio[0] < self.ASPECT_RATIO and human_angle in range(65, 115)):
status_score['Stand'] += 0.8
_weight = f'{_weight}, [4]Stand:+0.8'
elif (aspect_ratio[0] > 1 / self.ASPECT_RATIO): # 5/3
status_score['Fall'] += 0.8
_weight = f'{_weight}, [5]Fall:+0.8'
if vertical_threshold < self.Vertical_threshold:
status_score['Fall'] += 0.6
status_score['Sit'] += -0.15
if horizontal_threshold < self.Horizontal_threshold:
status_score['Fall'] += 0.6
status_score['Sit'] += -0.15
if 25 < Hip_Knee_Shoulders_angle[1] < 145 and 75 < human_angle <125:
status_score['Sit'] += 0.8
status_score['Stand'] += -0.035
if vertical_threshold > self.Vertical_threshold:
status_score['Sit'] += +0.15
_weight = f'{_weight}, [6]Stand:-0.035, Sit:+0.15'
elif Hip_Knee_Shoulders_angle[1] > 120 and 75 < human_angle <125:
status_score['Stand'] += 0.2
elif Hip_Knee_Shoulders_angle[1] > 120 and -25 < human_angle <25:
status_score['Fall'] += 0.2
else:
status_score['Fall'] += 0.05
status_score['Stand'] += 0.05
_weight = f'{_weight}, [7]Stand:+0.05, Fall:+0.05'
if 25 < Ankle_Knee_Hip_angle[1] < 145 and 45 < human_angle <125:
status_score['Sit'] += 0.8
status_score['Stand'] += -0.035
if vertical_threshold > self.Vertical_threshold:
status_score['Sit'] += +0.15
_weight = f'{_weight}, [8]Stand:+0.035, Sit:+0.15'
else:
status_score['Fall'] += 0.05
status_score['Stand'] += 0.05
_weight = f'{_weight}, [9]Stand:+0.05, Sit:+0.05'
if 65 < Hip_Knee_Right_angle[1] < 145 and 45 < human_angle <125:
status_score['Sit'] += 0.8
if vertical_threshold > self.Vertical_threshold:
status_score['Sit'] += +0.15
else:
status_score['Fall'] += 0.05
status_score['Stand'] += 0.05
print(_weight)
score_max, status_max = max(zip(status_score.values(), status_score.keys()))
'''输出计算参数'''
header = ['检测类型 ', '计算结果']
row = [['关键点',keypoints[0][:3]],
['肩部中心点',Shoulders_c],
['胯部中心点' ,hips_c],
['小腿中心点' ,Knee_c],
['肘部中心点' ,Ankle_c],
['身体中心线与水平线夹角', human_angle],
['宽高比', f'{aspect_ratio[0]} ,w:{aspect_ratio[1]} ,H:{aspect_ratio[2]}'],
['肩部中心点与胯部中心点的垂直距离差', human_shoulderhip],
['肩部胯部膝盖中心点夹角', Hip_Knee_Shoulders_angle],
['胯部膝盖小腿中心点夹角', Ankle_Knee_Hip_angle],
['右肩部胯部膝盖夹角', Hip_Knee_Right_angle],
['右胯部膝盖小腿夹角', Ankle_Knee_Right_angle],
['胯部膝盖是否处于相似的垂直位置', vertical_threshold],
['估计结果', status_score]]
print(tb(row, header, tablefmt='psql'))
return status_max
三、运行结果