【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的健身环大冒险一样!包括也搜了一些市面上成熟的产品,例如:魔镜(一个卖大几千),看着是同样的效果

相关推荐
欧特克_Glodon5 小时前
OpenCV计算机视觉开发入门与实践<十三>:图像转换之灰度图、二值图
c++·人工智能·opencv·计算机视觉
欧特克_Glodon5 小时前
OpenCV计算机视觉开发入门与实践<十二>:XML 和 YAML 文件读写
xml·c++·opencv·计算机视觉
TAN-90°-6 小时前
Deep Learning for Computer Vision——Training CNNs and CNN Architectures
人工智能·深度学习·神经网络·算法·机器学习·计算机视觉·cnn
小玮看世界15 小时前
从“画图”到“Mermaid”:AI语义理解与架构绘制的演进之路
人工智能·深度学习·计算机视觉
show43318 小时前
2026微信小程序视频转文字多语种识别引擎技术选型:22种方言25种外语挑战
微信小程序·小程序·音视频
诺....20 小时前
mkv转mp4并将字幕和音频烧进去
音视频
OH_TPC21 小时前
HarmonyOS APP开发---“股动力“实时行情App,需要用到这个库
华为·音视频·harmonyos·鸿蒙
碧海银沙音频科技研究院1 天前
ONNX 的全称Open Neural Network Exchange(开放神经网络交换格式)
人工智能·音视频·语音识别
IT小白杨1 天前
短视频多账号运营环境管理指南:指纹浏览器与云手机技术解析
大数据·经验分享·web安全·智能手机·音视频·指纹浏览器
人工智能研究所1 天前
正面硬刚 Seedance 2.5, 开源视频模型:LTX-2.5 用 6.8 秒生成 10 秒视频
人工智能·开源·音视频·文生视频·seedance·ltx-2.5