【mediapipe】实现卷腹运动识别(视频或摄像头)并计数

介绍

本人机器学习小白,通过语言大模型进行搜索,只用两小时不到就完成了该功能的初步效果,非常惊讶!比以往百度搜索的效率更高,结果也更准确。

思路

1.先通过mediapipe识别出人体关键节点

2.找到运动中会变化的节点,例如:我想实现卷腹计数,变化很大的节点就是膝盖

3.找到开始与结束时,关键节点的值,用来判断是否完成了一次动作

代码

python 复制代码
from time import sleep

import cv2
import mediapipe as mp

# 识别摄像头
def readCamara():
    # 初始化MediaPipe姿态检测对象
    mp_pose = mp.solutions.pose
    pose = mp_pose.Pose(static_image_mode=False, min_detection_confidence=0.5, min_tracking_confidence=0.5)

    # 打开摄像头获取视频流
    cap = cv2.VideoCapture(1)

    # 获取视频的帧率、宽度、高度等信息,用于设置输出视频参数
    fps = cap.get(cv2.CAP_PROP_FPS)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    # 设置输出视频的编码格式(这里使用XVID编码,常用的还有MJPG等,根据系统支持情况选择)
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    # 创建VideoWriter对象,用于保存输出视频,指定输出文件名、编码格式、帧率、视频尺寸
    out = cv2.VideoWriter('output_video.avi', fourcc, fps, (width, height))


    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        # 将图像转换为RGB格式(MediaPipe要求)
        image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        # 进行人体姿态检测
        results = pose.process(image_rgb)

        if results.pose_landmarks:
            # 遍历所有的人体姿态地标点
            for idx, landmark in enumerate(results.pose_landmarks.landmark):
                # 获取地标点的坐标(这里坐标是归一化的,范围0-1,后续可根据图像宽高转换为实际像素坐标)
                x = int(landmark.x * frame.shape[1])
                y = int(landmark.y * frame.shape[0])
                # 在画面上绘制地标点(用小圆圈表示)
                #cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)
                # 在地标点旁边显示对应的编号
                #cv2.putText(frame, str(idx), (x + 10, y + 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

        # 显示视频帧
        cv2.imshow('Frame', frame)
        # 将处理后的帧写入输出视频文件
        out.write(frame)
        if cv2.waitKey(1) & 0xFF == 27:  # 按ESC键退出
            break

    cap.release()
    cv2.destroyAllWindows()
    pose.close()

# 识别视频
def readVedio():

    # 用于记录初始膝盖位置纵坐标(这里简单以膝盖点24为例,也可综合考虑25等情况)
    initial_knee_y = 150
    # 卷腹计数
    complete_count = 0
    # 定义膝盖上升距离阈值(可根据实际情况调整),当膝盖上升超过此阈值认为可能完成一次卷腹
    distance_threshold = 150

    isCheck = False

    count = 0
    # 初始化MediaPipe姿态检测对象
    mp_pose = mp.solutions.pose
    pose = mp_pose.Pose(static_image_mode=False, min_detection_confidence=0.5, min_tracking_confidence=0.5)

    # 打开摄像头获取视频流
    cap = cv2.VideoCapture("./output_video.avi")


    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break

        count += 1

		# 这里是为了控制视频在指定的帧数范围才进行识别,提高调试的效率
        if count < 230 or count > 1000:
            continue
        print(count)

        # 将图像转换为RGB格式(MediaPipe要求)
        image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        # 进行人体姿态检测
        results = pose.process(image_rgb)

        if results.pose_landmarks:
            # 遍历所有的人体姿态地标点
            for idx, landmark in enumerate(results.pose_landmarks.landmark):
                # 获取地标点的坐标(这里坐标是归一化的,范围0-1,后续可根据图像宽高转换为实际像素坐标)
                x = int(landmark.x * frame.shape[1])
                y = int(landmark.y * frame.shape[0])
                if idx == 26 or idx == 25:
                    if isCheck == False:
                        if x <= 150:
                            isCheck = True
                    if isCheck == True:
                        if x - initial_knee_y > distance_threshold:
                            isCheck = False
                            complete_count += 1
                    print(idx,x,y)
                # 在画面上绘制地标点(用小圆圈表示)
                cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)
                # 在地标点旁边显示对应的编号
                cv2.putText(frame, str(idx), (x + 10, y + 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

            mp.solutions.drawing_utils.draw_landmarks(frame, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)

        # 在画面上显示计数结果
        cv2.putText(frame, f"Count: {complete_count}", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        # 显示视频帧
        cv2.imshow('Frame', frame)
        if cv2.waitKey(1) & 0xFF == 27:  # 按ESC键退出
            break
        #sleep(0.3)


    cap.release()
    cv2.destroyAllWindows()
    pose.close()


if __name__ == '__main__':
    readVedio()

效果


后续优化

目前是根据视频中膝盖最低点与最高点的差值来计算出是否完成一次运动,还存在一些弊端:

1.对视频的识别效果很好,但是通用性不强,当人离摄像头的远近不同时,其点位的值会同步发生变化

2.可以采用其他方式进行判断:

1.高地差的绝对值判断改为百分比判断

2.辅助其他节点进行判断,例如:膝盖的点(25,26)的x值大于等于臀部的点(23,24)的时候,记为完成一次运动

后记

根据该思路,可实现其他很多类的运动检测,如:俯卧撑,深蹲,等等,可通过计算百分比的值,播放不同的音乐,来让运动过程更有趣,就像 switch的健身环大冒险一样!包括也搜了一些市面上成熟的产品,例如:魔镜(一个卖大几千),看着是同样的效果

相关推荐
iteye_103922 小时前
ppt pptx转成pdf有什么好的java工具
音视频
AI视觉网奇3 小时前
pyhton 掩码 筛选显示
人工智能·opencv·计算机视觉
Struart_R5 小时前
DepthLab: From Partial to Complete 论文解读
人工智能·深度学习·计算机视觉·3d·深度估计·场景生成
小李学AI9 小时前
基于YOLOv8的恶劣天气目标检测系统
人工智能·深度学习·神经网络·yolo·目标检测·机器学习·计算机视觉
cxr82810 小时前
基于微信小程序的面部动作检测系统
人工智能·python·算法·计算机视觉·微信小程序·小程序·视觉检测
yoguo-21011 小时前
使用javacv获取海康威视rtsp流的详细教程
音视频
懒大王爱吃狼12 小时前
【Python】基于blind-watermark库添加图片盲水印
人工智能·python·opencv·计算机视觉·自动化·python基础·python教程
Learning改变世界12 小时前
矩阵运算提速——玩转opencv::Mat
人工智能·opencv·计算机视觉
阿松のblog14 小时前
深度学习之计算机视觉相关数据集
人工智能·深度学习·计算机视觉
跃跃欲试-迪之14 小时前
【视频配音加字幕】—— 让每一帧画面都“发声”!
音视频