基于mediapipe的姿态识别和简单行为识别

这篇具有很好参考价值的文章主要介绍了基于mediapipe的姿态识别和简单行为识别。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

学习目标

1、可以识别到人体姿态关键点

2、可以通过角度识别的方法识别到人体的动作(自定义)

源码地址:🚀🚀🚀🚀

一、mediapipe的安装

其实这部分很简单,直接在windows命令行的环境下

pip install mediepipe

就可以啦

二、使用mediapipe检测关键点

1、mediapipe的介绍

Mediapipe是一个用于构建机器学习管道的框架,用户处理视频、音频等时间序列数据。这个跨平台框架适用于桌面/服务器、Android、ios和各类嵌入式设备。
目前mediapipe包含16个solutions,分别为

人脸检测
Face Mesh
虹膜
手
姿态
人体
人物分割
头发分割
目标检测
Box Tracking
instant Motion Tracking
3D目标检测
特征匹配
AutoFlip
MediaSequence
YouTuBe_8M

mediapipe姿态识别,有意思的代码,python,计算机视觉,开发语言

总的来说,mediapipe是一个很好的库,可以解决我们处理ML项目中面临的大部分麻烦,而且很适合做行为识别方向的小伙伴练手使用。

2、使用mediapipe检测人体

这里仅使用mediapipe关于人体识别的方法(solution),谷歌官方将这种人体姿态识别的方法叫做Blazepose。

(0)检测前的准备工作

'''导入一些基本的库'''
import cv2
import mediapipe as mp
import time
from tqdm import tqdm
import numpy as np
from PIL import Image, ImageFont, ImageDraw
# ------------------------------------------------
#   mediapipe的初始化
# 	这一步是必须的,因为要使用到以下定义的几个类
# ------------------------------------------------
mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils
pose = mp_pose.Pose(static_image_mode=True)

(1)检测图片

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)
    # BRG-->RGB
    img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    # 将RGB图像输入模型,获取 关键点 预测结果
    results = pose.process(img_RGB)
    keypoints = ['' for i in range(33)]
    if results.pose_landmarks:
        mp_drawing.draw_landmarks(img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
        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)                                 # 得到最终的33个关键点
    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 = 1 / process_time                          # 帧率
    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]
        #if i in range(33):
        img = cv2.circle(img, (cx, cy), radius[i], colors[i], -1)
    '''str_pose = get_pos(keypoints)            #获取姿态
    cv2.putText(img, "POSE-{}".format(str_pose), (12, 100), cv2.FONT_HERSHEY_TRIPLEX,
                tl / 3, (255, 0, 0), thickness=tf)'''
    cv2.putText(img, "FPS-{}".format(str(int(fps))), (12, 100), cv2.FONT_HERSHEY_SIMPLEX,
                tl/3, (255, 255, 0),thickness=tf)
    return img

如果需要执行代码,则在文末的主函数中使用

if __name__ == '__main__':
	# 读取图片
	img0 = cv2.imread("./data/outImage--20.jpg")
	# 因为有中文路径,所以加上此行
    image = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), -1)
    img = image.copy()
    # 检测关键点,得到的image是检测过后的图片
    image = process_frame(img)
    # 使用matplotlib画图    
    fig, axes = plt.subplots(nrows=1, ncols=2)
    axes[0].imshow(img0[:,:,::-1])
    axes[0].set_title("原图")
    axes[1].imshow(image[:,:,::-1])
    axes[1].set_title("检测并可视化后的图片")
    plt.rcParams["font.sans-serif"] = ['SimHei']
    plt.rcParams["axes.unicode_minus"] = False
    plt.show()
    fig.savefig("./data/out.png")

最后附上检测效果。
mediapipe姿态识别,有意思的代码,python,计算机视觉,开发语言

(2)检测视频

任何不涉及3D卷积的机器视觉方法,检测视频其实就是检测图片。因为视频是由多帧图片融合得来的。
比如说一个30帧的视频,那么它的每一秒钟,就是由30张图片叠加而成。
将这些分割出的图片分别进行检测,最后将检测的图片进行融合,得到的就是检测后的视频。
有了这个依据,我们就可以把图片检测过程写成一个函数,在视频的每一帧中调用这个函数就可以啦
一般使用opencv库将视频分解为图片帧的形式,示例代码如下:

def video2image(videoPath="./video/demo1.mp4",
                image_dir="./image"):
    '''videoPath是视频路径, image_dir是图片保存的文件夹路径'''
    cap = cv2.VideoCapture(videoPath)
    frame_count = 0
    while(cap.isOpened()):
        success,frame = cap.read()
        if not success:
            break
        frame_count += 1
    print("视频总帧数:", frame_count)
    cap.release()
    cap = cv2.VideoCapture(videoPath)
    count = 0
    with tqdm(total=frame_count-1) as pbar:
        try:
            while(cap.isOpened()):
                success, frame = cap.read()
                if not success:
                    break
                #处理帧
                try:
                    if count % 20 == 0:
                        cv2.imwrite("{}/outImage--{}.jpg".format(image_dir, count), frame)
                except:
                    print("error")
                    pass
                if success == True:
                    pbar.update(1)
                    count+=1
        except:
            print("中途中断")
            pass
    cv2.destroyAllWindows()
    cap.release()
    print("视频已经处理结束,进行下一步操作!!!")

那么落实到本文想要实现的功能上,就可以在视频分解出的帧后面加上图片检测函数。
代码如下所示:

def process_video(video_path="./Data.mp4"):
    video_flag = False
    cap = cv2.VideoCapture(video_path)
    out_path = "./out_Data.mp4"
    print("视频开始处理……")
    frame_count = 0
    while (cap.isOpened()):
        success, frame = cap.read()
        frame_count += 1
        if not success:
            break
    cap.release()
    print("总帧数 = ", frame_count)
    cap = cv2.VideoCapture(video_path)
    if video_flag == False:
        frame_size = cap.get(cv2.CAP_PROP_FRAME_WIDTH), cap.get(cv2.CAP_PROP_FRAME_HEIGHT)  #处理图像的尺寸。
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')    #保存视频文件的格式为mp4
        fps = cap.get(cv2.CAP_PROP_FPS)
        out = cv2.VideoWriter(out_path, fourcc, fps, (int(frame_size[0]),int(frame_size[1])), ) #输出图像的句柄
    with tqdm(total=frame_count-1) as pbar:
        try:
            while cap.isOpened():
                success, frame = cap.read()
                if success:
                    pbar.update(1)
                    frame = process_frame(frame)					# frame就是视频截取的帧,process_frame表示对其检测。
                    cv2.namedWindow("frame", cv2.WINDOW_NORMAL)
                    cv2.imshow("frame", frame)
                    out.write(frame)
                    if cv2.waitKey(1) == 27:
                        break
                else:
                    break
        except:
            print("中途中断")
            pass
    cap.release()
    cv2.destroyAllWindows()
    out.release()
    print("视频已保存至", out_path)

有了视频的代码,那么就可以在主函数中对其进行调用,可视化效果就不展示了。

三、使用mediapipe-BlazePose检测自定义简单行为

1、原理介绍

将Mediapipe用于行为检测是比较复杂的一件事;如果这样做,那么行为检测的精度就完全取决于Mediapipe关键点的检测精度。
于是可以根据下图中人的关节夹角来对人的位姿进行检测。
mediapipe姿态识别,有意思的代码,python,计算机视觉,开发语言
如举手的时候,大臂与水平方向夹角是一定大于0度的。
叉腰的时候,双手垂下,大臂与小臂的夹角大于60度小于120度
那么这样就可以完成一些基本动作的分类。
我这里只列出几种比较简单的。
(1)举双手(2)举左手(3)举右手(4)叉腰(5)比三角形
先看一下效果图

mediapipe姿态识别,有意思的代码,python,计算机视觉,开发语言

2、实现过程

首先要知道,由坐标求得矢量的公式,其实就是两个坐标相减。
那么求两个矢量之间的夹角公式:
mediapipe姿态识别,有意思的代码,python,计算机视觉,开发语言
那么到代码中就是:

v1 = (x1, y1) - (x2, y2)
v2 = (x0, y0) - (x2, y2)
def get_angle(v1, v2):
    angle = np.dot(v1, v2) / (np.sqrt(np.sum(v1 * v1)) * np.sqrt(np.sum(v2 * v2)))
    angle = np.arccos(angle) / 3.14 * 180

    cross = v2[0] * v1[1] - v2[1] * v1[0]
    if cross < 0:
        angle = - angle
    return angle

这样就可以得到两个矢量的夹角。
之后,就可以通过夹角对行为进行判断,这里的规则是

举双手				左手矢量小于0右手矢量夹角大于0
举左手				左手矢量小于0右手矢量小于0
举右手				左手矢量大于0右手矢量大于0
比三角形				举双手的同时,大臂与小臂的夹角小于120度
正常				左手矢量大于0右手矢量夹角小于0
叉腰				正常情况下,左手肘夹角小于120度,右手肘夹角也小于0

给出的代码示例如下:

def get_pos(keypoints):
    str_pose = ""
    # 计算左臂与水平方向的夹角
    keypoints = np.array(keypoints)
    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)
    #计算左肘的夹角
    v1 = keypoints[11] - keypoints[13]
    v2 = keypoints[15] - keypoints[13]
    angle_left_elow = get_angle(v1, v2)
    # 计算右肘的夹角
    v1 = keypoints[12] - keypoints[14]
    v2 = keypoints[16] - keypoints[14]
    angle_right_elow = get_angle(v1, v2)

    if angle_left_arm<0 and angle_right_arm<0:
        str_pose = "LEFT_UP"
    elif angle_left_arm>0 and angle_right_arm>0:
        str_pose = "RIGHT_UP"
    elif angle_left_arm<0 and angle_right_arm>0:
        str_pose = "ALL_HANDS_UP"
        if abs(angle_left_elow)<120 and abs(angle_right_elow)<120:
            str_pose = "TRIANGLE"
    elif angle_left_arm>0 and angle_right_arm<0:
        str_pose = "NORMAL"
        if abs(angle_left_elow)<120 and abs(angle_right_elow)<120:
            str_pose = "AKIMBO"
    return str_pose

得到的str_pose就是行为字符串,在process_frame中可以在图片帧中可视化。
到这里,关键点检测与简单行为检测已经全部介绍结束了,如果实在复现不成的,可以直接看我代码仓库中的源码

计划:将在未来的博客里,把基于wxpython的UI设计与Mediapipe进行融合,实现可视化的交互过程,请持续关注。

学习之路逆水行舟,加油加油!!!文章来源地址https://www.toymoban.com/news/detail-786595.html

到了这里,关于基于mediapipe的姿态识别和简单行为识别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 记录-有意思的气泡 Loading 效果

    今日,群友提问,如何实现这么一个 Loading 效果: 这个确实有点意思,但是这是 CSS 能够完成的? 没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们之前的: 使用纯 CSS 实现超酷炫的粘性气泡效果 巧用 C

    2024年02月01日
    浏览(28)
  • 分享一组有意思的按钮设计

    先上效果图: 一共16个,每个都有自己不同的样式和效果,可以用在自己的项目中,提升客户体验~ 再上代码:

    2024年02月04日
    浏览(30)
  • 【动画进阶】有意思的网格下落渐次加载效果

    最近,群友贴了一个非常有意思的动画效果,整体动画效果如下: 点击某个按钮后,触发一个动画效果,原本的网格内容,将按顺序(又带点随机的效果)从高处下落进行加载填充动画。 当然,我个人认为这个动画有点华而不实,主要体现在这个动画一次需要耗费较长时间

    2024年02月16日
    浏览(30)
  • 涨姿势了,有意思的气泡 Loading 效果

    今日,群友提问,如何实现这么一个 Loading 效果: 这个确实有点意思,但是这是 CSS 能够完成的? 没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们之前的: 使用纯 CSS 实现超酷炫的粘性气泡效果 巧用 C

    2023年04月13日
    浏览(33)
  • 分享一个有意思的文字飞入动画(模仿水滴融合)

    先上效果图: 代码如下:

    2024年02月01日
    浏览(32)
  • 第五期:字符串的一些有意思的操作

    PS:每道题解题方法不唯一,欢迎讨论!每道题后都有解析帮助你分析做题,答案在最下面,关注博主每天持续更新。 1. 替换空格 题目描述 请实现一个函数,把字符串 s 中的每个空格替换成\\\"%20\\\"。 示例1: 输入:s = “We are happy.” 输出:“We%20are%20happy.” 示例2: 输入:s =

    2024年02月08日
    浏览(34)
  • 【动画进阶】有意思的 Emoji 3D 表情切换效果

    最近,群里面的同学发了这么一个非常有意思是动画效果: 原效果地址 -- CodePen Demo -- Letter Hop 当然,原效果,主要使用了 GSAP 动画库以及一个 3D 文字 JavaScript 库: 但是,这个效果,其实本身并不复杂。 本文,我们将不借助任何动画库,尝试用最简单的 CSS 和 JavaScript 代码还

    2024年02月14日
    浏览(25)
  • 有意思!一个关于 Spring 历史的在线小游戏

    发现 Spring One 的官网上有个好玩的彩蛋,分享给大家! 进到Spring One的官网,可以看到右下角有个类似马里奥游戏中的金币图标。 点击该金币之后,会打开一个新的页面,进入下面这样一个名为:The History Of Spring 的在线小游戏 你可以使用上下左右的方向键来控制Spring的Logo一

    2024年04月27日
    浏览(25)
  • kill 进程时遇到的一件有意思的事情

    一般来讲,我们在 kill 掉一个进程的时候通常有两个选择: 找到进程的 pid 号,然后执行 kill 命令 找到进程的名字,然后执行 pkill 命令 pkill 和 kill 命令都是向指定的进程发送信号,从而完成终结进程的操作,主要区别在于 pkill 命令与 pgrep 配套使用,能够踢出指定终端用户

    2023年04月10日
    浏览(30)
  • vue有意思的图片动画插件direction-reveal

    功能:操作简单好上头,动画特效很丝滑,有很多种供选择 导入到需要使用动画的单页面 使用样式 导入css,如果用到了scss就导入scss,用的css就导入.css文件 https://github.com/NigelOToole/direction-reveal 文章到此结束,希望对你有所帮助~

    2024年02月12日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包