针对羽毛球运动员训练视频,写一段程序识别羽毛球运动员的运动姿势,判断姿势是否标准。 标注骨骼四肢手脚动作,用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()