├── .DS_Store ├── Combat Simulation.sb3 ├── __pycache__ ├── helper.cpython-39.pyc ├── model.cpython-39.pyc ├── run.cpython-310.pyc └── run.cpython-39.pyc ├── data_collection.py ├── helper.py ├── model.py ├── move_dataset ├── crouch.pt ├── dataset.csv ├── hook.pt ├── kick.pt ├── no_move.pt └── special.pt ├── mp_test.py ├── play.py ├── run.md ├── run.py ├── test.py └── weights ├── trained_1.pt ├── trained_2.pt └── trained_3.pt /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/.DS_Store -------------------------------------------------------------------------------- /Combat Simulation.sb3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/Combat Simulation.sb3 -------------------------------------------------------------------------------- /__pycache__/helper.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/__pycache__/helper.cpython-39.pyc -------------------------------------------------------------------------------- /__pycache__/model.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/__pycache__/model.cpython-39.pyc -------------------------------------------------------------------------------- /__pycache__/run.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/__pycache__/run.cpython-310.pyc -------------------------------------------------------------------------------- /__pycache__/run.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/__pycache__/run.cpython-39.pyc -------------------------------------------------------------------------------- /data_collection.py: -------------------------------------------------------------------------------- 1 | # 导入相关的库 2 | import cv2, time, torch 3 | import mediapipe as mp 4 | # 从helper对象导入坐标提取(extract_coordinates) 5 | from helper import extract_coordinates 6 | 7 | # 创建一动作检测器相机 8 | # 创建一个摄像头 9 | My_Current_move = 'crouch' # 初始化当前动作 10 | Capture = cv2.VideoCapture(f'/users/zihan/your_path/{your_path}.mp4') # 创建一个摄像头:摄像头的路径 11 | #Capture = cv2.VideoCapture(0) # 创建一个摄像头 12 | start_time = time.time() # 初始化开始时间 13 | 14 | # OpenCV文本参数 15 | 16 | # 创建一个矩形框 17 | font = cv2.FONT_HERSHEY_SIMPLEX 18 | fontScale = 1 19 | 20 | # 矩形框的颜色:红色 21 | fontColor = (0,0,0) 22 | # 矩形框的线条宽度 23 | lineType = 4 24 | # 矩形框的线条类型 25 | # 设置时间 26 | setup_time = 0 27 | # 28 | s = True 29 | 30 | # Mediapipe姿势估计检测和绘制工具 31 | # 创建一个姿势估计检测器 32 | mpPose = mp.solutions.pose 33 | # 设置对象pose的属性 34 | pose = mpPose.Pose( 35 | # 图片基础模型 36 | static_image_mode=False, 37 | # 最小分类置信度 38 | min_detection_confidence=0.5, 39 | # 最小人脸检测置信度 40 | min_tracking_confidence=0.5 41 | ) 42 | 43 | # mp.solutions.drawing_utils用于绘制 44 | MP_draw = mp.solutions.drawing_utils 45 | 46 | # 动作标签字典 47 | labelmap = {'No_action':0, 'hook':1, 'kick':2, 'special':3, 'crouch':4} 48 | 49 | # 用于存储为移动收集的数据集的张量 50 | all_coords = torch.tensor([]) 51 | 52 | try : 53 | _ = True 54 | while _ : 55 | # 使用OpenCV读取框架 56 | _, frame = Capture.read() 57 | # 将图片转换为RGB格式 58 | frame = cv2.cvtColor(cv2.flip(frame,1), cv2.COLOR_BGR2RGB) 59 | # 提取姿势和坐标 60 | output = pose.process(frame) 61 | coords = extract_coordinates(output, mpPose) 62 | 63 | # 检查是否已过设置时间 64 | time_left = time.time() - start_time 65 | if time_left > setup_time : 66 | # 检测是否已经保存了数据集 67 | if s : 68 | # 检查当前帧中是否有要添加到数据集的姿势 69 | if coords : 70 | coords = torch.tensor(coords, dtype=torch.float32).unsqueeze(0) 71 | if all_coords.shape[0] == 0 : 72 | all_coords = coords 73 | else : 74 | all_coords = torch.cat([all_coords, coords], dim=0) 75 | # 标注文字 recording started 76 | cv2.putText(frame, 'recording started', (100,100), font, fontScale, fontColor, lineType=lineType, thickness=3) 77 | else : 78 | # 否则,如果设置时间尚未过去,则显示剩余时间 79 | if s : 80 | cv2.putText(frame, str(round(setup_time - time_left,2)), (100,100), font, fontScale, fontColor, lineType=lineType, thickness=3) 81 | 82 | # 绘制估计的地标和显示框 83 | MP_draw.draw_landmarks(frame, output.pose_landmarks, mpPose.POSE_CONNECTIONS) 84 | frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) 85 | cv2.imshow('output', frame) 86 | 87 | # 按下Q键退出 88 | if cv2.waitKey(1) & 0xFF == ord('q'): 89 | break 90 | # 如果捕获到异常,则退出 91 | except cv2.error : 92 | pass 93 | 94 | # 使用坐标保存张量,如果没有坐标,则保存空张量 95 | if all_coords.shape[0] > 0 : 96 | # 保存数据集:数据集的路径 97 | torch.save(all_coords, f'/your_path/move_dataset/{My_Current_move}.pt') 98 | # 打印保存的数据集的大小 99 | print(all_coords.shape) 100 | 101 | -------------------------------------------------------------------------------- /helper.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import mediapipe as mp 3 | import numpy as np 4 | from torchvision import transforms 5 | from statistics import mean 6 | from pynput.keyboard import Controller, Key 7 | 8 | # 创建键盘控制器 9 | keyboard = Controller() 10 | # 创建键盘按键绑定 11 | keybinds = {'hook':'j', 'kick':'k', 'special':'o', 'crouch':'s'} 12 | 13 | # 坐标提取方法 14 | def extract_coordinates(output, mpPose): 15 | output_list = [] 16 | lms_list = [ 17 | mpPose.PoseLandmark.NOSE, # 鼻子 18 | mpPose.PoseLandmark.RIGHT_SHOULDER, # 右肩 19 | mpPose.PoseLandmark.LEFT_SHOULDER, # 左肩 20 | mpPose.PoseLandmark.LEFT_ELBOW, # 左肘 21 | mpPose.PoseLandmark.RIGHT_ELBOW, # 右肘 22 | mpPose.PoseLandmark.LEFT_WRIST, # 左手腕 23 | mpPose.PoseLandmark.RIGHT_WRIST, # 右手腕 24 | mpPose.PoseLandmark.LEFT_PINKY, # 左手指 25 | mpPose.PoseLandmark.RIGHT_PINKY, # 右手指 26 | mpPose.PoseLandmark.LEFT_INDEX, # 左手指 27 | mpPose.PoseLandmark.RIGHT_INDEX, # 右手指 28 | mpPose.PoseLandmark.LEFT_THUMB, # 左手拇指 29 | mpPose.PoseLandmark.RIGHT_THUMB, # 右手拇指 30 | mpPose.PoseLandmark.LEFT_HIP, # 左臀 31 | mpPose.PoseLandmark.RIGHT_HIP, # 右臀 32 | mpPose.PoseLandmark.LEFT_KNEE, # 左膝 33 | mpPose.PoseLandmark.RIGHT_KNEE, # 右膝 34 | mpPose.PoseLandmark.LEFT_ANKLE, # 左脚踝 35 | mpPose.PoseLandmark.RIGHT_ANKLE, # 右脚踝 36 | ] 37 | 38 | # 取出 pose 坐标 39 | if output.pose_landmarks is not None : 40 | for lm in lms_list : 41 | landmark = output.pose_landmarks.landmark[lm] 42 | output_list.append(landmark.x) 43 | output_list.append(landmark.y) 44 | output_list.append(landmark.z) 45 | return output_list 46 | else : 47 | return False 48 | 49 | 50 | # 检测图片动作方法 51 | def detect_coordinates_img(imgs): 52 | # 输出结果列表 53 | output_tensor = [] 54 | for img in imgs : 55 | img = transforms.ToPILImage()(img) # 将 tensor 转换为 PIL 图片 56 | img = np.array(img) # 将 PIL 图片转换为 numpy 数组 57 | mpPose = mp.solutions.pose # 创建 mpPose 类 58 | # 创建 Pose 对象 59 | pose = mpPose.Pose( 60 | static_image_mode=True, # 图片模式 61 | min_detection_confidence=0.5 # 置信度 62 | ) 63 | output = pose.process(img) # 处理图片 64 | coords = extract_coordinates(output, mpPose) # 提取坐标 65 | if coords : 66 | output_tensor.append(coords) # 将坐标添加到输出结果列表 67 | 68 | return torch.tensor(output_tensor) # 返回输出结果 69 | 70 | # 71 | def move2keyboard(prev_coords, coords, move_detected): 72 | global keybinds # 全局变量 73 | global keyboard # 全局变量 74 | 75 | # 如果检测到动作 76 | if move_detected != 'No_action': 77 | # 按下键盘按键 78 | keyboard.press(keybinds[move_detected]) 79 | else : 80 | # 如果没有检测到动作 81 | threshold = 0.007 82 | body_center = mean(coords) # 计算坐标平均值 83 | prev_body_center = mean(prev_coords) # 计算上一帧坐标平均值 84 | if (body_center - prev_body_center)>threshold : # 如果坐标平均值大于阈值 85 | keyboard.press('d') # 按下 d 键 86 | elif (body_center - prev_body_center)<-(threshold) : # 如果坐标平均值小于阈值 87 | keyboard.press('a') # 按下 a 键 -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | # 姿态分类器 4 | class PoseClassification(torch.nn.Module): 5 | 6 | # 初始化 7 | def __init__(self, x_features, num_moves): # x_features: 图片特征数量,num_moves: 动作数量 8 | super(PoseClassification, self).__init__() # 继承父类 9 | self.model = torch.nn.Sequential( # 创建网络 10 | 11 | # 卷积层(1) 12 | torch.nn.Linear(x_features, 500), # 线性层 13 | torch.nn.BatchNorm1d(500), # 批归一化层 14 | torch.nn.ReLU(), # 激活层 15 | torch.nn.Dropout(p=0.2), # Dropout层 16 | 17 | # 卷积层(2) 18 | torch.nn.Linear(500,1000), # 线性层 19 | torch.nn.BatchNorm1d(1000), # 批归一化层 20 | torch.nn.ReLU(), # 激活层 21 | torch.nn.Dropout(p=0.2), # Dropout层 22 | 23 | # 卷积层(3) 24 | torch.nn.Linear(1000,1000), # 线性层 25 | torch.nn.BatchNorm1d(1000), # 批归一化层 26 | torch.nn.ReLU(), # 激活层 27 | torch.nn.Dropout(p=0.2), # Dropout层 28 | 29 | # 卷积层(4) 30 | torch.nn.Linear(1000,500), # 线性层 31 | torch.nn.BatchNorm1d(500), # 批归一化层 32 | torch.nn.ReLU(), # 激活层 33 | torch.nn.Dropout(p=0.2), # Dropout层 34 | 35 | # 卷积层(5) 36 | torch.nn.Linear(500,200), # 线性层 37 | torch.nn.BatchNorm1d(200), # 批归一化层 38 | torch.nn.ReLU(), # 激活层 39 | torch.nn.Dropout(p=0.2), # Dropout层 40 | 41 | # 卷积层(6) 42 | torch.nn.Linear(200,50), # 线性层 43 | torch.nn.BatchNorm1d(50), # 批归一化层 44 | torch.nn.ReLU(), # 激活层 45 | torch.nn.Dropout(p=0.2), # Dropout层 46 | 47 | # 卷积层(7) 48 | torch.nn.Linear(50,num_moves), # 线性层 49 | ) 50 | 51 | # 加载模型 52 | def forward(self,x): 53 | return self.model(x) 54 | 55 | # 姿态分类器测试 56 | def test(): 57 | 58 | # 模型初始化(图片特征数量60,动作数量4) 59 | model = PoseClassification(60,4) 60 | # 模型加载 61 | x = torch.randn((5,60)) 62 | 63 | # 模型输出 64 | output = model(x) 65 | 66 | # 打印模型输出维度 67 | print(f'Input shape : {x.shape}, Output shape : {output.shape}') -------------------------------------------------------------------------------- /move_dataset/crouch.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/move_dataset/crouch.pt -------------------------------------------------------------------------------- /move_dataset/hook.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/move_dataset/hook.pt -------------------------------------------------------------------------------- /move_dataset/kick.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/move_dataset/kick.pt -------------------------------------------------------------------------------- /move_dataset/no_move.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/move_dataset/no_move.pt -------------------------------------------------------------------------------- /move_dataset/special.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/move_dataset/special.pt -------------------------------------------------------------------------------- /mp_test.py: -------------------------------------------------------------------------------- 1 | import mediapipe as mp 2 | import cv2 3 | # 4 | def detect_img(img_path): 5 | img = cv2.imread(img_path) # 读取图片 6 | mpPose = mp.solutions.pose # 创建 mpPose 类 7 | pose = mpPose.Pose( # 创建 Pose 对象 8 | static_image_mode=True, # 图片模式 9 | min_detection_confidence=0.5 # 最小检测置信度 10 | ) 11 | MP_draw = mp.solutions.drawing_utils # 创建 MP_draw 类 12 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 将图片转换为RGB格式 13 | output = pose.process(img) # 输出检测姿势 14 | 15 | # 绘制姿势 16 | MP_draw.draw_landmarks(img, output.pose_landmarks, mpPose.POSE_CONNECTIONS) 17 | 18 | # 将图片转换为BGR格式 19 | img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) 20 | cv2.imshow('Output', img) # 显示图片 21 | cv2.waitKey(0) # 等待按键 22 | 23 | # 使用OpenCV读取视频框架 24 | def detect_video(): 25 | mpPose = mp.solutions.pose # 创建 mpPose 类 26 | pose = mpPose.Pose( # 创建 Pose 对象 27 | static_image_mode=False, # 视频模式 28 | min_detection_confidence=0.5, # 最小检测置信度 29 | min_tracking_confidence=0.5 # 最小追踪置信度 30 | ) 31 | MP_draw = mp.solutions.drawing_utils # 创建 MP_draw 类 32 | 33 | cap = cv2.VideoCapture(0) # 创建 VideoCapture 对象 34 | while True : # 循环 35 | _, img = cap.read() # 读取视频帧 36 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 将图片转换为RGB格式 37 | output = pose.process(img) # 输出检测姿势 38 | # 绘制姿势 39 | MP_draw.draw_landmarks(img, output.pose_landmarks, mpPose.POSE_CONNECTIONS) 40 | # 将图片转换为BGR格式 41 | img = cv2.cvtColor(cv2.flip(img,1), cv2.COLOR_RGB2BGR) 42 | cv2.imshow('Output', img) 43 | if cv2.waitKey(1) & 0xFF == ord('q'): # 等待按键 44 | break 45 | # 函数调用 46 | detect_video() -------------------------------------------------------------------------------- /play.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tkinter import * 3 | import tkinter.font as font 4 | from run import game_controller 5 | import os, sys 6 | 7 | # 图片路径(相对路径:当前文件所在目录, 图片名字) 8 | imgs_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tutorial_poses') 9 | 10 | # 创建窗口:展示游戏界面 11 | def img1(): 12 | Pic = tk.Toplevel() # 图片 13 | Pic.title("Rule 1") # 图片标题 14 | Pic.geometry("550x800") # 图片大小 15 | canvas1 = Canvas(Pic, width = 400, height = 800) # 创建画布 16 | img1 = PhotoImage(file=os.path.join(imgs_path, 'no_move.gif')) # 再次创建图片:重命名图片 17 | canvas1.create_image(20,20, anchor=NW, image=img1) # 在画布上添加图片 18 | canvas1.pack() # 将画布添加到窗口 19 | Pic.mainloop() # 展示图片窗口 20 | 21 | def img2(): # 创建图片2 22 | Pic = tk.Toplevel() # 图片 23 | Pic.title("Rule 2") # 图片标题 24 | Pic.geometry("550x750") # 图片大小 25 | canvas2 = Canvas(Pic, width = 900, height = 1200) # 创建画布 26 | img2 = PhotoImage(file=os.path.join(imgs_path, 'hook.gif')) # 再次创建图片:重命名图片 27 | canvas2.create_image(20,20, anchor=NW, image=img2) # 在画布上添加图片 28 | canvas2.pack() # 将画布添加到窗口 29 | Pic.mainloop() # 展示图片窗口 30 | 31 | def img3(): # 创建图片3 32 | Pic = tk.Toplevel() # 图片 33 | Pic.title("Rule 3") # 图片标题 34 | Pic.geometry("450x550") # 图片大小 35 | canvas3 = Canvas(Pic, width = 900, height = 500) # 创建画布 36 | canvas3.pack() # 将画布添加到窗口 37 | img3 = PhotoImage(file=os.path.join(imgs_path, 'kick.gif')) # 再次创建图片:重命名图片 38 | canvas3.create_image(20,20, anchor=NW, image=img3) # 在画布上添加图片 39 | canvas3.pack() # 将画布添加到窗口 40 | Pic.mainloop() # 展示图片窗口 41 | 42 | def img4(): # 创建图片4 43 | Pic = tk.Toplevel() # 图片 44 | Pic.title("Rule 4") # 图片标题 45 | Pic.geometry("550x750") # 图片大小 46 | canvas4 = Canvas(Pic, width = 900, height = 800) # 创建画布 47 | canvas4.pack() # 将画布添加到窗口 48 | img4 = PhotoImage(file=os.path.join(imgs_path, 'crouch.gif')) # 再次创建图片:重命名图片 49 | canvas4.create_image(20,20, anchor=NW, image=img4) # 在画布上添加图片 50 | canvas4.pack() 51 | Pic.mainloop() 52 | 53 | def img5(): # 创建图片5 54 | Pic = tk.Toplevel() # 图片 55 | Pic.title("Rule 5") # 图片标题 56 | Pic.geometry("550x750") # 图片大小 57 | canvas5 = Canvas(Pic, width = 900, height = 800) # 创建画布 58 | canvas5.pack() # 将画布添加到窗口 59 | img5 = PhotoImage(file=os.path.join(imgs_path, 'special.gif')) # 再次创建图片:重命名图片 60 | canvas5.create_image(20,20, anchor=NW, image=img5) # 在画布上添加图片 61 | canvas5.pack() # 将画布添加到窗口 62 | Pic.mainloop() # 展示图片窗口 63 | 64 | # 创建规则(应该是属性和内置方法) 65 | def create_rules(): 66 | rules = tk.Toplevel() # 图片 67 | rules.geometry("750x750") # 图片大小 68 | rules.title("How to Play") # 图片标题:规则 How to Play 69 | sb = Scrollbar(rules, orient = 'vertical') # 创建滚动条 70 | sb.pack(side = RIGHT, fill = Y) # 将滚动条添加到窗口 71 | 72 | # 按钮1 73 | r1 = Button(rules,text = "Rule 1",command = img1, fg='red',bg='blue',pady=1,padx=1) 74 | r1.place(x=100,y=200) # 将按钮添加到窗口的位置 75 | r1['font']= font.Font(size=10, weight="bold") # 设置字体大小和粗体 76 | 77 | # 按钮2 78 | r2 = Button(rules,text = "Rule 2",command = img2, fg='red',bg='blue',pady=1,padx=1) 79 | r2.place(x=200,y=200) # 将按钮添加到窗口的位置 80 | r2['font']= font.Font(size=10, weight="bold") # 设置字体大小和粗体 81 | 82 | # 按钮3 83 | r3 = Button(rules,text = "Rule 3",command = img3, fg='red',bg='blue',pady=1,padx=1) 84 | r3.place(x=300,y=200) # 将按钮添加到窗口的位置 85 | r3['font']= font.Font(size=10, weight="bold") # 设置字体大小和粗体 86 | 87 | r4 = Button(rules,text = "Rule 4",command = img4, fg='red',bg='blue',pady=1,padx=1) 88 | r4.place(x=400,y=200) # 将按钮添加到窗口的位置 89 | r4['font']= font.Font(size=10, weight="bold") # 设置字体大小和粗体 90 | 91 | r5 = Button(rules,text = "Rule 5",command = img5, fg='red',bg='blue',pady=1,padx=1) 92 | r5.place(x=500,y=200) # 将按钮添加到窗口的位置 93 | r5['font']= font.Font(size=10, weight="bold") # 设置字体大小和粗体 94 | 95 | L1 = Label(rules, text = "How 2 Play") # 创建标签 96 | L1.config(font =("Times New Roman", 20)) # 设置字体大小和粗体 97 | L1.config(anchor=CENTER) # 设置标签的位置 98 | L1.pack() # 将标签添加到窗口 99 | 100 | Tip1 = Label(rules, text = "1. 并排移动角色") # 创建标签 101 | Tip1.config(font =("Times New Roman", 12)) # 设置字体大小和粗体 102 | Tip1.config(anchor=CENTER) # 设置标签的位置 103 | Tip1.pack() # 将标签添加到窗口 104 | 105 | Tip2 = Label(rules, text = "2.抬起左臂执行冲床移动") 106 | Tip2.config(font =("Times New Roman", 12)) # 设置字体大小和粗体 107 | Tip2.config(anchor=CENTER) # 设置标签的位置 108 | Tip2.pack() 109 | 110 | 111 | Tip3 = Label(rules, text = "3.用腿踢腿,完成踢腿动作") 112 | Tip3.config(font =("Times New Roman", 12)) 113 | Tip3.config(anchor=CENTER) 114 | Tip3.pack() 115 | 116 | Tip4 = Label(rules, text = "4.Sqaut让你的角色俯冲下来 ") 117 | Tip4.config(font =("Times New Roman", 12)) 118 | Tip4.config(anchor=CENTER) 119 | Tip4.pack() 120 | 121 | Tip5 = Label(rules, text = "5.双手并拢,手掌伸开,伸出双臂进行特殊攻击") 122 | Tip5.config(font =("Times New Roman", 12)) 123 | Tip5.config(anchor=CENTER) 124 | Tip5.pack() 125 | 126 | rules.mainloop() # 主循环 127 | 128 | main = Tk() # 创建主窗口 129 | main.geometry("500x500") # 设置窗口大小 130 | main.title("Pose2Play") # 设置窗口标题 131 | 132 | LTitle = Label(main, text = "Pose2Play") # 创建标签 133 | LTitle.config(font =("Times New Roman", 30)) # 设置字体大小和粗体 134 | LTitle.config(anchor=CENTER) # 设置标签的位置 135 | LTitle.pack() # 将标签添加到窗口 136 | 137 | def exit_game(): # 定义退出函数 138 | sys.exit(0) # 退出程序 139 | 140 | # 打开游戏 141 | OpenGame = Button(main,text = "New \n Game",command = game_controller,fg='black',bg='blue',pady=10,padx=20) 142 | OpenGame.place(x=115,y=200) 143 | OpenGame['font']= font.Font(size=15, weight="bold") 144 | 145 | # 关闭游戏 146 | CloseGame = Button(main,text = "Close \n Game",command = exit_game,fg='black',bg='blue',pady=10,padx=20) 147 | CloseGame.place(x=265,y=200) 148 | CloseGame['font']= font.Font(size=15, weight="bold") 149 | 150 | # 游戏规则 151 | GameRules = Button(main,text = "How Do You Play?",command = create_rules,fg='black',bg='blue',pady=7.5,padx=20) 152 | GameRules.place(x=175,y=350) 153 | GameRules['font']= font.Font(size=9, weight="bold") 154 | 155 | # 主循环 156 | main.mainloop() 157 | -------------------------------------------------------------------------------- /run.md: -------------------------------------------------------------------------------- 1 | 运行方式: 运行Play.py就行了 2 | 3 | 安装的库安装一下就可以了,mediapip 最新版也没问题 4 | 5 | 我这里运行可以 6 | 7 | 然后这个是点集运行完了以后点击 new game 8 | 9 | 结束游戏就点击一下这个视频界面: 再按英文 q 就行 10 | 11 | 12 | 13 | 这个run.py是这个启动程序的子程序,运行没有结果,我把这几个打包到 14 | 15 | play.py 里面了,之前这两个是分开的,我全都调试完了以后,就是没效果 16 | 17 | 现在没问题了 18 | 19 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | 2 | # 游戏控制器 3 | def game_controller(): 4 | # 初始化游戏 5 | import torch, cv2, time, os 6 | from model import PoseClassification 7 | from helper import extract_coordinates, move2keyboard 8 | import mediapipe as mp 9 | time.sleep(3) # 等待3秒 10 | 11 | # 设置模型路径 12 | model_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'weights/trained_2.pt') 13 | model = PoseClassification(57, 5) # 创建一个姿态检测器模型 14 | model.load_state_dict(torch.load(model_path, map_location='cpu')) # 加载模型 调用CPU 15 | model = model.eval() # 设置模型为评估模式 16 | 17 | # 姿势字典{'No_action':无行动, 'hook':挂钩, 'kick':踢球, 'special':特殊动作, 'crouch':蹲下} 18 | move2id = {'No_action': 0, 'hook': 1, 'kick': 2, 'special': 3, 'crouch': 4} 19 | id2move = {x: y for y, x in move2id.items()} # 反向字典 20 | 21 | scale = 0.65 # 缩放比例 22 | font = cv2.FONT_HERSHEY_SIMPLEX # 字体 23 | fontScale = 0.75 # 字体大小 24 | fontColor = (255, 255, 255) # 字体颜色 25 | lineType = 4 # 线条类型 26 | 27 | Capture = cv2.VideoCapture(0) # 创建一个视频捕获对象 28 | h = int(Capture.get(4)) # 获取视频高度 29 | w = int(Capture.get(3)) # 获取视频宽度 30 | mpPose = mp.solutions.pose # 创建一个姿态检测器 31 | pose = mpPose.Pose( # 创建一个姿态检测器 32 | static_image_mode=False, # 开启动态图像模式 33 | min_detection_confidence=0.5, # 设置检测置信度 34 | min_tracking_confidence=0.5 # 设置跟踪置信度 35 | ) 36 | MP_draw = mp.solutions.drawing_utils # 创建一个绘图工具 37 | 38 | prev_movement_coords = [] # 上一帧的姿势坐标 39 | ptime = 0 # 上一帧的时间 40 | The_current_time = 0 # 当前帧的时间 41 | 42 | while True: # 循环 43 | _, frame = Capture.read() # 读取一帧视频 44 | # frame = cv2.cvtColor(cv2.flip(frame, 1), cv2.COLOR_BGR2RGB) 45 | frame = cv2.cvtColor(cv2.flip(frame, 1), cv2.COLOR_BGR2RGB) # 反转图像 46 | try: 47 | output = pose.process(frame) # 姿态检测 48 | MP_draw.draw_landmarks(frame, output.pose_landmarks, mpPose.POSE_CONNECTIONS) # 绘制姿态关键点 49 | coords = extract_coordinates(output, mpPose) # 提取姿势坐标 50 | if coords: # 如果有姿势坐标 51 | coords = torch.tensor(coords).unsqueeze(0) # 将坐标转换为张量 52 | yhat = model(coords).view(-1) # 预测姿势 53 | yhat_ = torch.argmax(yhat) # 预测姿势 54 | conf = round(yhat[yhat_].item(), 5) # 预测置信度 55 | pred = id2move[yhat_.item()] # 预测姿势 56 | if pred == 'kick' and conf < 3: # 如果预测为踢腿 57 | pred = 'No_action' # 将预测姿势设置为无行动 58 | elif pred == 'special' and conf < 2: # 如果预测为特殊动作 59 | pred = 'No_action' # 将预测姿势设置为无行动 60 | cv2.rectangle(frame, (0, h), (w - 1000, h - 110), (0, 0, 0), -1, 1) # 绘制矩形 61 | cv2.putText(frame, f'Move : {pred}', (0, h - 80), font, fontScale, fontColor, lineType=lineType, 62 | thickness=2) # 绘制文字 63 | cv2.putText(frame, f'Confidence : {conf}', (0, h - 50), font, fontScale, fontColor, lineType=lineType, 64 | thickness=2) # 绘制文字 65 | 66 | if len(prev_movement_coords) != 0: # 如果有上一帧的姿势坐标 67 | movement_coords = [coords[0][3].item(), coords[0][6].item()] # 获取姿势坐标 68 | move2keyboard(prev_movement_coords, movement_coords, pred) # 将姿势坐标传递给键盘 69 | prev_movement_coords = movement_coords # 更新上一帧的姿势坐标 70 | else: # 如果没有上一帧的姿势坐标 71 | prev_movement_coords = [coords[0][3].item(), coords[0][6].item()] # 更新上一帧的姿势坐标 72 | 73 | except cv2.error: # 如果检测失败 74 | pass # 继续循环 75 | 76 | The_current_time = time.time() # 获取当前时间 77 | fps = round(1 / (The_current_time - ptime), 2) # 计算帧率 78 | ptime = The_current_time # 更新时间 79 | cv2.putText(frame, f'FPS : {str(fps)}', (0, h - 20), font, fontScale, fontColor, lineType=lineType, thickness=2) # 绘制文字 80 | 81 | frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) # 反转图像 82 | new_dims = (int(w * scale), int(h * scale)) # 设置缩放尺寸 83 | frame = cv2.resize(frame, new_dims) # 缩放图像 84 | cv2.imshow('Output', frame) # 显示图像 85 | 86 | if cv2.waitKey(1) & 0xFF == ord('q'): # 如果按下q键 87 | break # 退出循环 88 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import mediapipe as mp 3 | import os 4 | import time 5 | import torch 6 | 7 | from helper import extract_coordinates 8 | from model import PoseClassification 9 | 10 | # 创建一动作检测器相机 11 | My_model_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'weights/trained_2.pt') 12 | model = PoseClassification(57,5) # 创建一个摄像头 13 | model.load_state_dict(torch.load(My_model_path, map_location='cpu')) # 加载模型 14 | model = model.eval() # 设置模型为验证模式 15 | 16 | Move_two_ID = {'No_action':0, 'hook':1, 'kick':2, 'special':3, 'crouch':4}# 动作标签字典 17 | id2move = {x:y for y,x in Move_two_ID.items()} # 反向字典 18 | 19 | scale = 1 # 缩放比例 20 | font = cv2.FONT_HERSHEY_SIMPLEX # 字体 21 | fontScale = 0.75 # 字体大小 22 | fontColor = (255,255,255) # 字体颜色 23 | lineType = 4 # 线条类型 24 | 25 | cap = cv2.VideoCapture(0) # 创建一个摄像头 26 | h = int(cap.get(4)) # 获取摄像头的高 27 | w = int(cap.get(3)) # 获取摄像头的宽 28 | mpPose = mp.solutions.pose # 创建一个Pose类 29 | pose = mpPose.Pose( # 创建一个Pose类 30 | static_image_mode=False, # 动态图像模式 31 | min_detection_confidence=0.5, # 检测置信度 32 | min_tracking_confidence=0.5 # 跟踪置信度 33 | ) 34 | MP_draw = mp.solutions.drawing_utils # 创建一个画图类 35 | 36 | prev_movement_coords = [] # 上一帧的动作坐标 37 | ptime = 0 # 上一帧的时间 38 | The_current_time = 0 # 当前帧的时间 39 | 40 | while True : # 循环 41 | _, frame = cap.read() # 读取一帧 42 | frame = cv2.cvtColor(cv2.flip(frame, 1), cv2.COLOR_BGR2RGB) # 转换颜色空间 43 | try : # 尝试 44 | output = pose.process(frame) # 获取一帧的动作坐标 45 | MP_draw.draw_landmarks(frame, output.pose_landmarks, mpPose.POSE_CONNECTIONS) # 画出动作坐标 46 | coords = extract_coordinates(output, mpPose) # 提取动作坐标 47 | if coords : # 如果有动作坐标 48 | coords = torch.tensor(coords).unsqueeze(0) # 将坐标转换为张量 49 | yhat = model(coords).view(-1) # 预测动作 50 | yhat_ = torch.argmax(yhat) # 预测动作 51 | conf = round(yhat[yhat_].item(),5) # 预测动作的置信度 52 | pred = id2move[yhat_.item()] # 预测动作 53 | 54 | if pred == 'kick' and conf < 3 : # 如果预测动作为踢球 55 | pred = 'No_action' # 将预测动作设置为无动作 56 | elif pred == 'special' and conf < 2 : # 如果预测动作为特殊动作 57 | pred = 'No_action' # 将预测动作设置为无动作 58 | 59 | cv2.rectangle(frame, (0,h), (w-1000,h-110), (0,0,0), -1, 1) # 画出框 60 | cv2.putText(frame, f'Move : {pred}', (0,h-80), font, fontScale, fontColor, lineType=lineType, thickness=2) # 显示动作 61 | cv2.putText(frame, f'Confidence : {conf}', (0,h-50), font, fontScale, fontColor, lineType=lineType, thickness=2) # 显示置信度 62 | 63 | except AttributeError : # 如果没有动作坐标 64 | pass # 继续循环 65 | 66 | The_current_time = time.time() # 获取当前时间 67 | fps = round(1/(The_current_time-ptime),2) # 计算FPS 68 | ptime = The_current_time # 记录上一帧时间 69 | cv2.putText(frame, f'FPS : {str(fps)}', (0, h-20), font, fontScale, fontColor, lineType=lineType, thickness=2) # 显示FPS 70 | 71 | frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) # 转换颜色空间 72 | new_dims = (int(w * scale), int(h * scale)) # 计算缩放后的尺寸 73 | frame = cv2.resize(frame, new_dims) # 缩放图像 74 | cv2.imshow('Output', frame) # 显示图像 75 | 76 | if cv2.waitKey(1) & 0xFF == ord('q'): # 按q退出 77 | break 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /weights/trained_1.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/weights/trained_1.pt -------------------------------------------------------------------------------- /weights/trained_2.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/weights/trained_2.pt -------------------------------------------------------------------------------- /weights/trained_3.pt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zihan987/pose-game-python/8b6db763adcb1a9509a490aeb1f9dc7d5262d2d3/weights/trained_3.pt --------------------------------------------------------------------------------