运行效果
基于Mediapipe的手势识别,完成的手势识别游戏。运行效果图如下:
首先是初始的界面效果图:
游戏规则:屏幕上会出现蚊子和蜜蜂,当手蜷曲握起时,表示抓的动作。如果抓到右边移动的蚊子,则会增加分数,如果抓到右边的蜜蜂,则会出现被蛰到的声音 :)
代码介绍
调用Mediapipe,定义与手势识别有关的类:
这里完成了对图片镜像的翻转,在图上画出手势线条,并对手势的握起状态逻辑进行判断。
import cv2
import mediapipe as mp
from settings import *
import numpy as np
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands
class HandTracking:
def __init__(self):
self.hand_tracking = mp_hands.Hands(min_detection_confidence=0.5, min_tracking_confidence=0.5)
self.hand_x = 0
self.hand_y = 0
self.results = None
self.hand_closed = False
def scan_hands(self, image):
rows, cols, _ = image.shape
# Flip the image horizontally for a later selfie-view display, and convert
# the BGR image to RGB.
image = cv2.cvtColor(cv2.flip(image, 1), cv2.COLOR_BGR2RGB)
# To improve performance, optionally mark the image as not writeable to
# pass by reference.
image.flags.writeable = False
self.results = self.hand_tracking.process(image)
# Draw the hand annotations on the image.
image.flags.writeable = True
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
self.hand_closed = False
print(self.results.multi_hand_landmarks)
if self.results.multi_hand_landmarks:
for hand_landmarks in self.results.multi_hand_landmarks:
x, y = hand_landmarks.landmark[9].x, hand_landmarks.landmark[9].y
self.hand_x = int(x * SCREEN_WIDTH)
self.hand_y = int(y * SCREEN_HEIGHT)
x1, y1 = hand_landmarks.landmark[12].x, hand_landmarks.landmark[12].y
if y1 > y:
self.hand_closed = True
mp_drawing.draw_landmarks(
image,
hand_landmarks,
mp_hands.HAND_CONNECTIONS,
mp_drawing_styles.get_default_hand_landmarks_style(),
mp_drawing_styles.get_default_hand_connections_style())
return image
def get_hand_center(self):
return (self.hand_x, self.hand_y)
def display_hand(self):
cv2.imshow("image", self.image)
cv2.waitKey(1)
def is_hand_closed(self):
pass
定义游戏类:
这里导入了音效和背景,并加载界面上方的分数和剩余时间等。
import pygame
import time
import random
from settings import *
from background import Background
from hand import Hand
from hand_tracking import HandTracking
from mosquito import Mosquito
from bee import Bee
import cv2
import ui
class Game:
def __init__(self, surface):
self.surface = surface
self.background = Background()
# Load camera
self.cap = cv2.VideoCapture(0)
self.sounds = {}
self.sounds["slap"] = pygame.mixer.Sound(f"Assets/Sounds/slap.wav")
self.sounds["slap"].set_volume(SOUNDS_VOLUME)
self.sounds["screaming"] = pygame.mixer.Sound(f"Assets/Sounds/screaming.wav")
self.sounds["screaming"].set_volume(SOUNDS_VOLUME)
def reset(self): # reset all the needed variables
self.hand_tracking = HandTracking()
self.hand = Hand()
self.insects = []
self.insects_spawn_timer = 0
self.score = 0
self.game_start_time = time.time()
def spawn_insects(self):
t = time.time()
if t > self.insects_spawn_timer:
self.insects_spawn_timer = t + MOSQUITOS_SPAWN_TIME
# increase the probability that the insect will be a bee over time
nb = (GAME_DURATION-self.time_left)/GAME_DURATION * 100 / 2 # increase from 0 to 50 during all the game (linear)
if random.randint(0, 100) < nb:
self.insects.append(Bee())
else:
self.insects.append(Mosquito())
# spawn a other mosquito after the half of the game
if self.time_left < GAME_DURATION/2:
self.insects.append(Mosquito())
def load_camera(self):
_, self.frame = self.cap.read()
def set_hand_position(self):
self.frame = self.hand_tracking.scan_hands(self.frame)
(x, y) = self.hand_tracking.get_hand_center()
self.hand.rect.center = (x, y)
def draw(self):
# draw the background
self.background.draw(self.surface)
# draw the insects
for insect in self.insects:
insect.draw(self.surface)
# draw the hand
self.hand.draw(self.surface)
# draw the score
ui.draw_text(self.surface, f"Score : {self.score}", (5, 5), COLORS["score"], font=FONTS["medium"],
shadow=True, shadow_color=(255,255,255))
# draw the time left
timer_text_color = (160, 40, 0) if self.time_left < 5 else COLORS["timer"] # change the text color if less than 5 s left
ui.draw_text(self.surface, f"Time left : {self.time_left}", (SCREEN_WIDTH//2, 5), timer_text_color, font=FONTS["medium"],
shadow=True, shadow_color=(255,255,255))
def game_time_update(self):
self.time_left = max(round(GAME_DURATION - (time.time() - self.game_start_time), 1), 0)
def update(self):
self.load_camera()
self.set_hand_position()
self.game_time_update()
self.draw()
if self.time_left > 0:
self.spawn_insects()
(x, y) = self.hand_tracking.get_hand_center()
self.hand.rect.center = (x, y)
self.hand.left_click = self.hand_tracking.hand_closed
print("Hand closed", self.hand.left_click)
if self.hand.left_click:
self.hand.image = self.hand.image_smaller.copy()
else:
self.hand.image = self.hand.orig_image.copy()
self.score = self.hand.kill_insects(self.insects, self.score, self.sounds)
for insect in self.insects:
insect.move()
else: # when the game is over
if ui.button(self.surface, 540, "Continue", click_sound=self.sounds["slap"]):
return "menu"
cv2.imshow("Frame", self.frame)
cv2.waitKey(1)
定义与手势动作相关的动作类:
import pygame
import image
from settings import *
from hand_tracking import HandTracking
import cv2
class Hand:
def __init__(self):
self.orig_image = image.load("Assets/hand.png", size=(HAND_SIZE, HAND_SIZE))
self.image = self.orig_image.copy()
self.image_smaller = image.load("Assets/hand.png", size=(HAND_SIZE - 50, HAND_SIZE - 50))
self.rect = pygame.Rect(SCREEN_WIDTH//2, SCREEN_HEIGHT//2, HAND_HITBOX_SIZE[0], HAND_HITBOX_SIZE[1])
self.left_click = False
#self.hand_tracking = HandTracking()
def follow_mouse(self): # change the hand pos center at the mouse pos
self.rect.center = pygame.mouse.get_pos()
#self.hand_tracking.display_hand()
def follow_mediapipe_hand(self, x, y):
self.rect.center = (x, y)
def draw_hitbox(self, surface):
pygame.draw.rect(surface, (200, 60, 0), self.rect)
def draw(self, surface):
image.draw(surface, self.image, self.rect.center, pos_mode="center")
if DRAW_HITBOX:
self.draw_hitbox(surface)
def on_insect(self, insects): # return a list with all insects that collide with the hand hitbox
return [insect for insect in insects if self.rect.colliderect(insect.rect)]
def kill_insects(self, insects, score, sounds): # will kill the insects that collide with the hand when the left mouse button is pressed
if self.left_click: # if left click
for insect in self.on_insect(insects):
insect_score = insect.kill(insects)
score += insect_score
sounds["slap"].play()
if insect_score < 0:
sounds["screaming"].play()
else:
self.left_click = False
return score
定义与蚊子移动有关的类:
首先从图片中导入了蚊子的形状信息,并让蚊子随机的进行上下左右移动
import pygame
import random
import time
import image
from settings import *
class Mosquito:
def __init__(self):
#size
random_size_value = random.uniform(MOSQUITO_SIZE_RANDOMIZE[0], MOSQUITO_SIZE_RANDOMIZE[1])
size = (int(MOSQUITOS_SIZES[0] * random_size_value), int(MOSQUITOS_SIZES[1] * random_size_value))
# moving
moving_direction, start_pos = self.define_spawn_pos(size)
# sprite
self.rect = pygame.Rect(start_pos[0], start_pos[1], size[0]//1.4, size[1]//1.4)
self.images = [image.load("Assets/mosquito/mosquito.png", size=size, flip=moving_direction=="right")]
self.current_frame = 0
self.animation_timer = 0
def define_spawn_pos(self, size): # define the start pos and moving vel of the mosquito
vel = random.uniform(MOSQUITOS_MOVE_SPEED["min"], MOSQUITOS_MOVE_SPEED["max"])
moving_direction = random.choice(("left", "right", "up", "down"))
if moving_direction == "right":
start_pos = (-size[0], random.randint(size[1], SCREEN_HEIGHT-size[1]))
self.vel = [vel, 0]
if moving_direction == "left":
start_pos = (SCREEN_WIDTH + size[0], random.randint(size[1], SCREEN_HEIGHT-size[1]))
self.vel = [-vel, 0]
if moving_direction == "up":
start_pos = (random.randint(size[0], SCREEN_WIDTH-size[0]), SCREEN_HEIGHT+size[1])
self.vel = [0, -vel]
if moving_direction == "down":
start_pos = (random.randint(size[0], SCREEN_WIDTH-size[0]), -size[1])
self.vel = [0, vel]
return moving_direction, start_pos
def move(self):
self.rect.move_ip(self.vel)
def animate(self): # change the frame of the insect when needed
t = time.time()
if t > self.animation_timer:
self.animation_timer = t + ANIMATION_SPEED
self.current_frame += 1
if self.current_frame > len(self.images)-1:
self.current_frame = 0
def draw_hitbox(self, surface):
pygame.draw.rect(surface, (200, 60, 0), self.rect)
def draw(self, surface):
self.animate()
image.draw(surface, self.images[self.current_frame], self.rect.center, pos_mode="center")
if DRAW_HITBOX:
self.draw_hitbox(surface)
def kill(self, mosquitos): # remove the mosquito from the list
mosquitos.remove(self)
return 1
另外,手势识别相关的基础内容,可以参考评论区的这个博客文章来源:https://www.toymoban.com/news/detail-500514.html
需要源码(10r)的可以邮箱私信我 yangsober@163.com文章来源地址https://www.toymoban.com/news/detail-500514.html
到了这里,关于基于Mediapipe的Python手势识别项目(手势识别游戏)附项目源码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!