基与yoloV8姿态检测实现坐、站立、跌倒姿态推理评估(含源代码)

一、环境安装
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

三、运行结果




 

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值