基于人体姿态估计的opencv动作识别与动作分类

这是一个使用 库进行实时人体姿态识别的 Python 脚本。它通过计算人体关键点来识别不同的姿势,然后在图像中标注出关键点并显示当前姿势。

主要步骤包括:

  1. 导入所需的库和模块,和 OpenCV。
  2. 定义了一些辅助函数,用于计算角度、绘制文本等。
  3. 定义了处理帧的函数 process_frame,该函数接收视频帧并进行姿态识别、关键点标注、姿势判断等处理。
  4. 定义了预处理图像和保存图像的函数 pre_imagesave_image
  5. 主函数中打开摄像头,循环读取摄像头帧,调用处理帧函数,并显示处理后的帧,直到按下键盘上的任意键退出程序。

这个脚本可以实现实时的姿态识别和展示,可以用于监控、体感互动等应用场景。

Pose中的地标模型预测了33个地标的位置(见下图)。
在这里插入图片描述

姿态识别是计算机视觉领域的一个重要分支,它通过分析图像或视频中的人体动作来识别人物的姿态。在日常生活中,不同的姿态可以传达出不同的情感和意图。下面将介绍几种常见的姿态:“叉腰站立”、“比三角”、“举左后”和“举右手”。

  1. 叉腰站立
    叉腰站立是一种常见且富有表现力的姿态。当一个人双手握拳并置于腰部两侧时,通常表示自信、强势或不满的情绪。这种姿势有时也出现在放松的场景中,比如人们在等待或者思考问题的时候。从技术角度来看,识别这一姿态需要检测人体的关键点,特别是肩膀、肘部和手腕的位置关系。当算法确认左右手分别靠近相应的髋关节,并且手臂形成一定的角度时,就可以判断为叉腰。
    在这里插入图片描述

  2. 比三角
    “比三角”的姿态指的是人用身体模仿出一个三角形的形状。这可能涉及双臂伸展成V字形,或者是单手与腿部构成三角结构。这个姿态可能是为了表达某种艺术性的构图或是参与特定的游戏和活动。在姿态识别中,实现对“比三角”的准确识别,依赖于对人体骨架模型中各关节位置的理解,以及这些关节之间形成的几何关系是否符合预设的三角形标准。
    在这里插入图片描述

  3. 举左后
    举左后是指将左臂向后抬起的动作。这种姿态可以在体育运动(如游泳准备动作)、舞蹈或是日常生活中见到。对于计算机视觉系统而言,识别此姿态的关键在于捕捉到左肩相对于躯干的角度变化,以及左手腕相对于头部、肩部和其他肢体部分的空间位置。同时,还需要考虑手臂抬高的程度和方向,以确保正确区分其他类似但不完全相同的手臂上举动作。
    在这里插入图片描述

  4. 举右手
    举右手是一个简单而直接的姿态,广泛应用于各种场合,例如课堂上的提问、交通指挥中的停止手势等。要识别这一姿态,主要关注右臂的垂直度、手掌的方向及其相对于脸部或其他身体部位的位置。此外,还需考虑到环境因素的影响,比如光照条件、背景复杂性等,这些都会影响到图像处理的效果,从而间接影响姿态识别的准确性。

综上所述,姿态识别不仅涉及到对人体结构的理解,还要求能够精准地捕捉和解析复杂的动态信息。随着深度学习技术和传感器精度的不断提高,姿态识别的应用范围正在迅速扩大,包括但不限于虚拟现实、智能监控、医疗康复等领域。未来,随着技术的进步,我们可以期待更加准确、实时且多功能的姿态识别解决方案。

在这里插入图片描述

代码定义

以下是您提供的代码每一部分的注解说明:


#  代码定义

```python


# 定义一个计算两个向量之间角度的函数
def get_angle(v1, v2):
    # 使用向量点积公式计算两个向量之间的弧度角
    angle_rad = np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))
    # 将弧度转换为度数
    angle_deg = np.arccos(angle_rad) / np.pi * 180
    # 根据叉积判断并修正角度方向(顺时针或逆时针)
    cross_product = v2[0] * v1[1] - v2[1] * v1[0]
    if cross_product < 0:
        angle_deg = -angle_deg
    return angle_deg

# ------------------------------------------------
#   计算姿态信息
# ------------------------------------------------
def get_pos(keypoints):
    # 初始化姿态字符串
    str_pose = ""
    
    # 计算左臂与水平方向的夹角
    v1 = keypoints[12] - keypoints[11]  # 上臂向量(肩到肘)
    v2 = keypoints[13] - keypoints[11]  # 整条左臂向量(肩到手)
    angle_left_arm = get_angle(v1, v2)

    # 计算右臂与水平方向的夹角
    v1 = keypoints[11] - keypoints[12]  # 上臂向量(肩到肘)
    v2 = keypoints[14] - keypoints[12]  # 整条右臂向量(肩到手)
    angle_right_arm = get_angle(v1, v2)

    # 计算左右手肘关节内部夹角
    angle_left_elow = get_angle(keypoints[11] - keypoints[13], keypoints[15] - keypoints[13])
    angle_right_elow = get_angle(keypoints[12] - keypoints[14], keypoints[16] - keypoints[14])

    # 计算两个手肘中心点坐标
    elbow_center_x = (keypoints[11][0] + keypoints[12][0]) / 2
    elbow_center_y = (keypoints[11][1] + keypoints[12][1]) / 2

    # 计算两个手腕中心点坐标
    wrist_center_x = (keypoints[15][0] + keypoints[16][0]) / 2
    wrist_center_y = (keypoints[15][1] + keypoints[16][1])

    # 计算两个手肘与手腕之间的直线距离
    distance_elbow_wrist = math.sqrt((wrist_center_x - elbow_center_x)**2 + (wrist_center_y - elbow_center_y)**2)

    # 根据左右手臂角度判断具体姿态
    if angle_left_arm < 0 and angle_right_arm < 0:
        str_pose = "LEFT_UP"
        print(0)
    elif angle_left_arm > 0 and angle_right_arm > 0:
        str_pose = "RIGHT_UP"
        print(1)
    elif angle_left_arm < 0 and angle_right_arm > 0:
        str_pose = "ALL_HANDS_UP"
        print(2)
        if abs(angle_left_elow) < 120 and abs(angle_right_elow) < 120:
            str_pose = "TRIANGLE"
            print(3)
    elif angle_left_arm > 0 and angle_right_arm < 0:
        str_pose = "NORMAL"
        print(4)
        if abs(angle_left_elow) < 120 and abs(angle_right_elow) < 120:
            str_pose = "AKIMBO"
            print(5)
    elif distance_elbow_wrist < 0.1:  # 距离近似相等,视为水平一字手势
        str_pose = "水平"

    return str_pose

# 定义一个将文字绘制到图像上的函数
def drawImage(im, chinese, pos, color):
    # 将OpenCV图像转为PIL格式,以便使用ImageDraw进行文本绘制
    img_PIL = Image.fromarray(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))

    # 设置字体文件及字体大小,并指定编码
    font = ImageFont.truetype('simsun.ttc', 100, encoding="utf-8")

    # 设置填充颜色
    fillColor = color  # (255,0,0)

    # 设置文本位置
    position = pos  # (100,100)

    # 创建绘图对象并绘制文本
    draw = ImageDraw.Draw(img_PIL)
    draw.text(position, chinese, fillColor, font)

    # 将绘制了文本的PIL图像转回OpenCV格式
    img = cv2.cvtColor(np.asarray(img_PIL), cv2.COLOR_RGB2BGR)
    return img

# 定义一个处理单帧图像的函数
def process_frame(img):
    # 开始计时
    start_time = time.time()

    # 获取图像的高度和宽度
    h, w = img.shape[0], img.shape[1]

    # 根据图像尺寸调整字体大小
    tl = round(0.005 * (img.shape[0] + img.shape[1]) / 2) + 1
    tf = max(tl - 1, 1)

    # 将BGR图像转为RGB,供MediaPipe模型使用
    img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    # 对图像执行关键点检测
    results = pose.process(img_RGB)

    # 初始化存放33个人体关键点坐标的列表
    keypoints = ['' for _ in range(33)]

    # 如果检测到关键点,则在图像上绘制关键点连线
    

        # 计算每个关键点的像素坐标,并存入列表
        for i in range(33):
            cx = int(results.pose_landmarks.landmark[i].x * w)
            cy = int(results.pose_landmarks.landmark[i].y * h)
            keypoints[i] = (cx, cy)

    # 若未检测到人,则在图像上写入“NO PERSON”字样
    else:
        print("NO PERSON")
        struction = "NO PERSON"
        img = cv2.putText(img, struction, (25, 100), cv2.FONT_HERSHEY_SIMPLEX, 1.25, (255, 255, 0), 6)

    # 结束计时并计算关键点预测所用时间
    end_time = time.time()
    process_time = end_time - start_time

    # 计算每秒帧数(FPS)
    fps = 1 / process_time

    # 为33个关键点随机分配颜色和半径
    colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(33)]
    radius = [random.randint(8, 15) for _ in range(33)]

    # 绘制彩色圆圈标注各个关键点
    for i in range(33):
        cx, cy = keypoints[i]
        img = cv2.circle(img, (cx, cy), radius[i], colors[i], -1)

        # 计算当前帧的姿态信息
        str_pose = get_pos(keypoints)

 

    # 返回处理后的图像
    return  img



985计算机硕:代码获取/论文指导/远程协助/课程设计
文章底部卡片扫码


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值