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

相关推荐
张子夜 iiii2 小时前
实战项目-----Python+OpenCV 实现对视频的椒盐噪声注入与实时平滑还原”
开发语言·python·opencv·计算机视觉
小王爱学人工智能3 小时前
OpenCV的图像金字塔
人工智能·opencv·计算机视觉
Zender Han4 小时前
Flutter 视频播放器——flick_video_player 介绍与使用
android·flutter·ios·音视频
@areok@4 小时前
C++mat传入C#OpencvCSharp的mat
开发语言·c++·opencv·c#
max5006005 小时前
实时多模态电力交易决策系统:设计与实现
图像处理·人工智能·深度学习·算法·音视频
虚行8 小时前
VisionMaster - 1.图像源
人工智能·计算机视觉
FutureUniant9 小时前
GitHub每日最火火火项目(9.10)
人工智能·microsoft·计算机视觉·ai·github
这张生成的图像能检测吗9 小时前
(论文速读)从语言模型到通用智能体
人工智能·计算机视觉·语言模型·自然语言处理·多模态·智能体
WeiJingYu.10 小时前
O3.1 opencv高阶
人工智能·opencv·计算机视觉
格林威10 小时前
工业相机如何通过光度立体成像技术实现高效精准的2.5D缺陷检测
人工智能·深度学习·数码相机·yolo·计算机视觉