羽毛球运动员的运动姿势-标准动作识别判断

针对羽毛球运动员训练视频,写一段程序识别羽毛球运动员的运动姿势,判断姿势是否标准。 标注骨骼四肢手脚动作,用Python实现的代码,同时在视频中计算移动距离。运动员是在羽毛球场进行训练,训练周边有球场划线作为参考。

说明

上述代码中,我们增加了 calculate_distance 函数,用于计算运动员的移动距离。在循环处理视频帧的过程中,每次检测到人体关节点坐标时,都会调用这个函数来计算移动距离,并输出结果。此外,我们还优化了 check_pose 函数,使其更加简洁易读。

badminton_training

针对羽毛球运动员训练视频,写一段程序识别羽毛球运动员的运动姿势,判断姿势是否标准。 标注骨骼四肢手脚动作,用Python实现的代码,同时在视频中计算移动距离。运动员是在羽毛球场进行训练,训练周边有球场划线作为参考

考虑点

OpenPose 和 MediaPipe Pose 都是非常流行的实时姿态估计库,它们在性能和准确性方面有各自的优缺点。

准确性: OpenPose 通常被认为在准确性方面更胜一筹,特别是在处理复杂数字姿势、遮挡和多人场景时。这主要归功于其强大的深度学习模型和优化算法。但这也意味着 OpenPose 通常需要更多的计算资源和时间来实现更高的准确性。 MediaPipe Pose 准确性相对较低,但在大多数场景下,它仍能提供足够的准确性,尤其是在单人场景和不太复杂数字姿势的情况下。它的优势在于更快的处理速度和更低的计算资源需求。

性能: MediaPipe Pose 在性能方面表现更好,因为它旨在为实时应用程序提供较低的延迟和较高的帧速率。MediaPipe 专注于在移动设备和边缘计算设备上实现实时性能。因此,如果性能和实时性能是您的首要考虑因素,MediaPipe 可能是更好的选择。 OpenPose 在性能方面相对较差,因为它需要较多的计算资源和时间来处理图像和视频。然而,如果准确性是您的首要考虑因素,并且您拥有足够的计算能力,OpenPose 是一个非常好的选择。

总结起来,根据您的应用需求和硬件条件来决定使用哪个库。如果您需要较高的准确性并且拥有足够的计算能力,可以选择 OpenPose。如果您追求实时性能和较低的计算资源消耗,特别是在移动或边缘计算设备上,MediaPipe Pose 可能是更好的选择。

badminton_pose.py
import cv2
import mediapipe as mp
import math

# 初始化姿势检测模型
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()

# 读取视频
cap = cv2.VideoCapture('badminton_training.mp4')

# 初始化计数器和列表存储运动员坐标
counter = 0
coords = []


# 定义运动姿势判断函数
def check_pose(coords):
    # 设定关键关节点坐标阈值
    thresholds = {
        'shoulder': 30,
        'elbow': 20,
        'wrist': 15,
        'hip': 30,
        'knee': 20,
        'ankle': 15
    }

    # 关键点索引
    keypoints = {
        'left_shoulder': 11,
        'right_shoulder': 12,
        'left_elbow': 13,
        'right_elbow': 14,
        'left_wrist': 15,
        'right_wrist': 16,
        'left_hip': 23,
        'right_hip': 24,
        'left_knee': 25,
        'right_knee': 26,
        'left_ankle': 27,
        'right_ankle': 28
    }

    # 判断关键点间的距离
    for key, threshold in thresholds.items():
        key_parts = key.split('_')
        left_keypoint = keypoints[f"left_{key_parts[0]}"]
        right_keypoint = keypoints[f"right_{key_parts[0]}"]
        if abs(coords[left_keypoint][0] - coords[right_keypoint][0]) > threshold:
            print(f'{key_parts[0].capitalize()}距离过大,姿势不标准')
        else:
            print(f'{key_parts[0].capitalize()}距离正常')


# 计算运动员移动距离
def calculate_distance(coords):
    if len(coords) >= 2:
        last_frame = coords[-2]
        current_frame = coords[-1]
        hip_center_last = [(last_frame[23][0] + last_frame[24][0]) / 2, (last_frame[23][1] + last_frame[24][1]) / 2]
        hip_center_current = [(current_frame[23][0] + current_frame[24][0]) / 2,
                              (current_frame[23][1] + current_frame[24][1]) / 2]
        distance = math.sqrt((hip_center_current[0] - hip_center_last[0]) ** 2 + (
                hip_center_current[1] - hip_center_last[1]) ** 2)
        return distance
    else:
        return 0


# 循环检测视频中的每一帧
while cap.isOpened():
    # 读取帧
    ret, frame = cap.read()

    # 如果读取帧成功,进行检测
    if ret:

        # 将当前帧发送到Pose检测模型
        results = pose.process(frame)

        # 如果检测到人体,获取人体关节点的坐标
        if results.pose_landmarks:
            # 获取当前帧中人体关节点的相关坐标
            landmark_coords = []
            for _, landmark in enumerate(results.pose_landmarks.landmark):
                landmark_coords.append([landmark.x, landmark.y, landmark.z, landmark.visibility])

            # 将当前人体坐标添加到总坐标列表中
            coords.append(landmark_coords)

            # 根据坐标列表判断姿势
            check_pose(coords)

            # 计算移动距离
            distance = calculate_distance(coords)
            print(f'移动距离: {distance}')

            # 显示当前帧并标注关键点
            mp_pose.draw_landmarks(
                frame,
                results.pose_landmarks,
                mp_pose.POSE_CONNECTIONS
            )

        # 显示图像
        cv2.imshow('MediaPipe Pose', frame)

        # 如果q键被按下,退出循环
        if cv2.waitKey(10) & 0xFF == ord('q'):
            break

        # 增加帧计数器
        counter += 1

# 释放资源
cap.release()
cv2.destroyAllWindows()
spider.py
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException

from bs4 import BeautifulSoup
import requests

from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

# 如果使用的是Chrome无头浏览器
options = webdriver.ChromeOptions()
options.add_argument('headless')
options.add_argument('window-size=1200x600')  # Optional

driver = webdriver.Chrome(chrome_options=options)


#执行到64的时候出错了,不知道原因
for idxDoc in range(199,300):
    sUrl = f"https://h5.40dhjen.cn/catalogue?id={idxDoc}"
    response = requests.get(sUrl)
    #页面不存在跳过
    if response.status_code == 404:
        print(sUrl,"不存在")
        continue

    driver.get(response.url)
    driver.implicitly_wait(20) 
    try:
        WebDriverWait(driver, 20).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "taro-view-core.catalogue-list-item.hydrated"))
        )
    except TimeoutException as e:
        print(sUrl,"没有获取成功")
        continue
    taro_views = driver.find_elements(By.CSS_SELECTOR, 'taro-view-core.catalogue-list-item.hydrated')
    raro_size = len(taro_views)
    title = driver.title

    print("当前循环索引:",idxDoc, "\n文件数量:",raro_size,"文章名:",title)

    for idx in range(0,raro_size):
        txt = taro_views[idx].text
        print(f"文件名:{txt}")

        taro_views[idx].click()

        driver.implicitly_wait(20)
        # 不是具体的页面跳过
        if "catalogue" in driver.current_url:
            break
        
        try:
            WebDriverWait(driver, 20).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, "taro-view-core.book-article-paragraph.hydrated"))
            )
        except TimeoutException as e:
            print(driver.current_url,"没有获取成功")
            # 返回原页面
            driver.back()
            driver.implicitly_wait(20)
            taro_views = driver.find_elements(By.CSS_SELECTOR, 'taro-view-core.catalogue-list-item.hydrated')
            continue

        filename = f"{title}{idx:03d}{txt}.md" 
        # 获取新页面的内容
        new_html = driver.page_source
        new_soup = BeautifulSoup(new_html, 'html.parser')

        # 提取book-article-paragraph类的元素并写入文件
        paragraphs = new_soup.select('taro-view-core.book-article-paragraph.hydrated')
        with open(filename, 'w', encoding='utf-8') as file:
            for paragraph in paragraphs:
                file.write(paragraph.text + '\n')

        # 返回原页面
        driver.back()
        driver.implicitly_wait(20)
        taro_views = driver.find_elements(By.CSS_SELECTOR, 'taro-view-core.catalogue-list-item.hydrated')

driver.quit()

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值