PiscCode構建Mediapipe 手勢識別“剪刀石頭布”小游戲

在計算機視覺與人機交互領域,手勢識別是一個非常有趣的應用場景。本文將帶你用 MediapipePython 實現一個基于攝像頭的手勢識別“剪刀石頭布”小游戲,并展示實時手勢與游戲結果。


1. 項目概述

該小游戲能夠實現:

  1. 實時檢測手勢,包括 石頭(Rock)剪刀(Scissors)布(Paper)OK手勢

  2. 玩家展示 OK 手勢時重置游戲。

  3. 當玩家展示 R/P/S 手勢時,與電腦隨機出拳進行比對,顯示勝負結果。

  4. 在攝像頭畫面上繪制手部關鍵點和手勢文字,同時在屏幕左上角顯示電腦出拳和本輪結果。

整個項目的核心依賴:

  • mediapipe:用于手部關鍵點檢測。

  • opencv-python:用于攝像頭讀取與圖像顯示。

  • numpy:用于手勢判斷的數學計算。

  • random:模擬電腦出拳。


2. 核心類:SimpleHandGestureGame

class SimpleHandGestureGame:def __init__(self, model_path="hand_landmarker.task", num_hands=1):# 初始化 Mediapipe HandLandmarkerbase_options = python.BaseOptions(model_asset_path=model_path)options = vision.HandLandmarkerOptions(base_options=base_options, num_hands=num_hands)self.detector = vision.HandLandmarker.create_from_options(options)self.computer_choice = Noneself.round_result = ""self.round_played = False

2.1 手勢繪制 _draw_landmarks

def _draw_landmarks(self, rgb_image, detection_result):annotated_image = np.copy(rgb_image)if detection_result.hand_landmarks:for hand_landmarks in detection_result.hand_landmarks:proto_landmarks = landmark_pb2.NormalizedLandmarkList()proto_landmarks.landmark.extend([landmark_pb2.NormalizedLandmark(x=lm.x, y=lm.y, z=lm.z) for lm in hand_landmarks])solutions.drawing_utils.draw_landmarks(image=annotated_image,landmark_list=proto_landmarks,connections=mp.solutions.hands.HAND_CONNECTIONS,landmark_drawing_spec=solutions.drawing_styles.get_default_hand_landmarks_style(),connection_drawing_spec=solutions.drawing_styles.get_default_hand_connections_style())return annotated_image

2.2 手勢識別 _judge_gesture

我們通過手指關鍵點的伸直狀態判斷手勢:

  • 石頭(Rock):全部手指彎曲

  • 剪刀(Scissors):食指和中指伸直,其他彎曲

  • 布(Paper):五指全部伸直

  • OK:拇指與食指形成圓圈,其余三指伸直

def _judge_gesture(self, hand_landmarks):def is_straight(tip, pip, mcp=None):if mcp:a, b, c = np.array([tip.x, tip.y]), np.array([pip.x, pip.y]), np.array([mcp.x, mcp.y])ba, bc = a - b, c - bcos_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc) + 1e-6)return np.arccos(np.clip(cos_angle, -1, 1)) * 180 / np.pi > 160else:return tip.y < pip.ythumb_straight = is_straight(hand_landmarks[4], hand_landmarks[2], hand_landmarks[1])index_straight = is_straight(hand_landmarks[8], hand_landmarks[6])middle_straight = is_straight(hand_landmarks[12], hand_landmarks[10])ring_straight = is_straight(hand_landmarks[16], hand_landmarks[14])pinky_straight = is_straight(hand_landmarks[20], hand_landmarks[18])total = sum([thumb_straight, index_straight, middle_straight, ring_straight, pinky_straight])# OK gesturethumb_tip, index_tip = np.array([hand_landmarks[4].x, hand_landmarks[4].y]), np.array([hand_landmarks[8].x, hand_landmarks[8].y])if np.linalg.norm(thumb_tip - index_tip) < 0.05 and middle_straight and ring_straight and pinky_straight:return "OK"if total == 0: return "Rock"if total == 2 and index_straight and middle_straight: return "Scissors"if total == 5: return "Paper"return "Undefined"

2.3 游戲邏輯 _play_game

def _play_game(self, player_choice):choices = ["Rock", "Scissors", "Paper"]if self.computer_choice is None:self.computer_choice = random.choice(choices)if player_choice == self.computer_choice:self.round_result = "Draw"elif (player_choice == "Rock" and self.computer_choice == "Scissors") or \(player_choice == "Scissors" and self.computer_choice == "Paper") or \(player_choice == "Paper" and self.computer_choice == "Rock"):self.round_result = "You Win"else:self.round_result = "Computer Wins"self.round_played = True

2.4 圖像處理 do

最終的 do 方法負責:

  1. 讀取攝像頭幀

  2. 調用 Mediapipe 檢測手勢

  3. 繪制手部關鍵點和手勢文字

  4. 顯示電腦出拳及勝負結果

def do(self, frame, device=None):if frame is None: return Nonemp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))detection_result = self.detector.detect(mp_image)annotated = self._draw_landmarks(mp_image.numpy_view(), detection_result)# ...繪制手勢文字和游戲結果...return cv2.cvtColor(annotated, cv2.COLOR_RGB2BGR)

3. 快速體驗

import cv2
import numpy as np
import mediapipe as mp
from mediapipe import solutions
from mediapipe.framework.formats import landmark_pb2
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
import randomclass SimpleHandGestureGame:def __init__(self, model_path="文件地址/hand_landmarker.task", num_hands=1):"""Initialize Mediapipe HandLandmarker and game state"""base_options = python.BaseOptions(model_asset_path=model_path)options = vision.HandLandmarkerOptions(base_options=base_options, num_hands=num_hands)self.detector = vision.HandLandmarker.create_from_options(options)self.computer_choice = Noneself.round_result = ""self.round_played = Falsedef _draw_landmarks(self, rgb_image, detection_result):annotated_image = np.copy(rgb_image)if detection_result.hand_landmarks:for hand_landmarks in detection_result.hand_landmarks:proto_landmarks = landmark_pb2.NormalizedLandmarkList()proto_landmarks.landmark.extend([landmark_pb2.NormalizedLandmark(x=lm.x, y=lm.y, z=lm.z) for lm in hand_landmarks])solutions.drawing_utils.draw_landmarks(image=annotated_image,landmark_list=proto_landmarks,connections=mp.solutions.hands.HAND_CONNECTIONS,landmark_drawing_spec=solutions.drawing_styles.get_default_hand_landmarks_style(),connection_drawing_spec=solutions.drawing_styles.get_default_hand_connections_style())return annotated_imagedef _judge_gesture(self, hand_landmarks):"""Determine hand gesture: Rock-Paper-Scissors + OK"""def is_straight(tip, pip, mcp=None):if mcp:a, b, c = np.array([tip.x, tip.y]), np.array([pip.x, pip.y]), np.array([mcp.x, mcp.y])ba, bc = a - b, c - bcos_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc) + 1e-6)return np.arccos(np.clip(cos_angle, -1, 1)) * 180 / np.pi > 160else:return tip.y < pip.ythumb_straight = is_straight(hand_landmarks[4], hand_landmarks[2], hand_landmarks[1])index_straight = is_straight(hand_landmarks[8], hand_landmarks[6])middle_straight = is_straight(hand_landmarks[12], hand_landmarks[10])ring_straight = is_straight(hand_landmarks[16], hand_landmarks[14])pinky_straight = is_straight(hand_landmarks[20], hand_landmarks[18])thumb, index, middle, ring, pinky = thumb_straight, index_straight, middle_straight, ring_straight, pinky_straighttotal = sum([thumb, index, middle, ring, pinky])# OK gesturethumb_tip, index_tip = np.array([hand_landmarks[4].x, hand_landmarks[4].y]), np.array([hand_landmarks[8].x, hand_landmarks[8].y])if np.linalg.norm(thumb_tip - index_tip) < 0.05 and middle and ring and pinky:return "OK"# Rock-Paper-Scissorsif total == 0:return "Rock"if total == 2 and index and middle:return "Scissors"if total == 5:return "Paper"return "Undefined"def _play_game(self, player_choice):"""Determine the result of Rock-Paper-Scissors round"""choices = ["Rock", "Scissors", "Paper"]if self.computer_choice is None:self.computer_choice = random.choice(choices)if player_choice == self.computer_choice:self.round_result = "Draw"elif (player_choice == "Rock" and self.computer_choice == "Scissors") or \(player_choice == "Scissors" and self.computer_choice == "Paper") or \(player_choice == "Paper" and self.computer_choice == "Rock"):self.round_result = "You Win"else:self.round_result = "Computer Wins"self.round_played = Truedef do(self, frame, device=None):"""Process a single frame, overlay hand gesture and game result (vertically)"""if frame is None:return Nonemp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))detection_result = self.detector.detect(mp_image)annotated = self._draw_landmarks(mp_image.numpy_view(), detection_result)gesture_display = ""if detection_result.hand_landmarks:for hand_landmarks in detection_result.hand_landmarks:gesture = self._judge_gesture(hand_landmarks)if gesture == "OK":self.computer_choice = random.choice(["Rock", "Scissors", "Paper"])self.round_result = ""self.round_played = Falsegesture_display = "Game Ready..."elif gesture in ["Rock", "Scissors", "Paper"] and not self.round_played:self._play_game(gesture)gesture_display = f"{gesture}"else:gesture_display = gestureh, w, _ = annotated.shapeindex_finger_tip = hand_landmarks[8]cx, cy = int(index_finger_tip.x * w), int(index_finger_tip.y * h)cv2.putText(annotated, gesture_display, (cx, cy - 20), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2)if self.round_result:start_x, start_y, line_height = 30, 50, 40lines = [f"Computer Choice: {self.computer_choice}", f"Result: {self.round_result}"]for i, line in enumerate(lines):cv2.putText(annotated, line, (start_x, start_y + i * line_height), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 255), 3)return cv2.cvtColor(annotated, cv2.COLOR_RGB2BGR)

4. 總結

本文展示了如何用 Mediapipe HandLandmarker 快速搭建一個實時手勢識別小游戲。通過關鍵點計算與簡單邏輯判斷,實現了石頭、剪刀、布和 OK 手勢識別,并結合游戲邏輯輸出結果。

對 PiscTrace or PiscCode感興趣?更多精彩內容請移步官網看看~🔗?PiscTrace

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/95626.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/95626.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/95626.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【VoNR】VoNR 不等于 VoLTE on 5G

博主未授權任何人或組織機構轉載博主任何原創文章&#xff0c;感謝各位對原創的支持&#xff01; 博主鏈接 本人就職于國際知名終端廠商&#xff0c;負責modem芯片研發。 在5G早期負責終端數據業務層、核心網相關的開發工作&#xff0c;目前牽頭6G技術研究。 博客內容主要圍繞…

計算機網絡:網絡設備在OSI七層模型中的工作層次和傳輸協議

OSI七層模型&#xff08;物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層&#xff09;中&#xff0c;不同網絡設備因功能不同&#xff0c;工作在不同層次。以下是典型網絡設備的工作層次及核心功能&#xff1a;1. 物理層&#xff08;第1層&#xff09; 核心功能&a…

RSA-e和phi不互素

1.題目import gmpy2 import libnum p 1656713884642828937525841253265560295123546793973683682208576533764344166170780019002774068042673556637515136828403375582169041170690082676778939857272304925933251736030429644277439899845034340194709105071151095131704526…

基于單片機蒸汽壓力檢測/蒸汽余熱回收

傳送門 &#x1f449;&#x1f449;&#x1f449;&#x1f449;單片機作品題目速選一覽表&#x1f680; &#x1f449;&#x1f449;&#x1f449;&#x1f449;單片機作品題目功能速覽&#x1f680; &#x1f525;更多文章戳&#x1f449;小新單片機-CSDN博客&#x1f68…

https 協議與 wss 協議有什么不同

HTTPS 是用于網頁數據傳輸的安全協議&#xff0c;而 WSS 是用于實時雙向通信&#xff08;如聊天、直播&#xff09;的安全協議&#xff0c;二者的設計目標、應用場景、底層邏輯均存在本質區別。以下從 7 個核心維度展開對比&#xff0c;并補充關鍵關聯知識&#xff0c;幫助徹底…

主流分布式數據庫集群選型指南

以下是關于主流分布式可擴展數據庫集群的詳細解析&#xff0c;涵蓋技術分類、代表產品及適用場景&#xff0c;幫助您高效選型&#xff1a;一、分布式數據庫核心分類 1. NewSQL 數據庫&#xff08;強一致性 分布式事務&#xff09;產品開發方核心特性適用場景TiDBPingCAPHTAP架…

#T1359. 圍成面積

題目描述編程計算由“*”號圍成的下列圖形的面積。面積計算方法是統計*號所圍成的閉合曲線中水平線和垂直線交點的數目。如下圖所示&#xff0c;在1010的二維數組中&#xff0c;有“*”圍住了15個點&#xff0c;因此面積為15。輸入1010的圖形。輸出輸出面積。樣例輸入數據 10 0…

Hive on Tez/Spark 執行引擎對比與優化

在大數據開發中,Hive 已經成為最常用的數據倉庫工具之一。隨著業務數據規模的不斷擴大,Hive 默認的 MapReduce 執行引擎 顯得笨重低效。為了提升查詢性能,Hive 支持了 Tez 和 Spark 作為底層執行引擎。本文將帶你對比 Hive on Tez 與 Hive on Spark 的區別,并分享調優經驗。…

深入理解 Next.js 的路由機制

深入理解 Next.js 的路由機制 作者&#xff1a;碼力無邊在上一篇文章中&#xff0c;我們成功創建并運行了第一個 Next.js 應用。當你打開項目文件夾時&#xff0c;你可能會注意到一個名為 pages 的目錄。這個目錄看似普通&#xff0c;但它卻是 Next.js 路由系統的核心。今天&am…

modbus_tcp和modbus_rtu對比移植AT-socket,modbus_tcp雜記

modbus_rtu通信時沒有連接過程&#xff0c;主機和從機各自初始化自身串口就行了&#xff0c;而rtu需要確定從機ID。注:在TCP連接中&#xff0c;不同的網卡有不同的IP&#xff0c;port對應具體的程序。/* 先讀取數據 */for (i 0; i < len; i){if (pdPASS ! xQueueReceive(re…

Docker Compose 詳解:從安裝到使用的完整指南

在現代容器化應用開發中&#xff0c;Docker Compose 是一個不可或缺的工具&#xff0c;它能夠幫助我們輕松定義和運行多容器的 Docker 應用程序。 一、什么是 Docker Compose&#xff1f; Docker Compose 是 Docker 官方提供的一個工具&#xff0c;用于定義和運行多容器 Dock…

springboot配置多數據源(mysql、hive)

MyBatis-Plus 不能也不建議同時去“控制” Hive。它從設計到實現都假定底層是 支持事務、支持標準 SQL 方言 的 關系型數據庫&#xff08;MySQL、PostgreSQL、Oracle、SQL Server 等&#xff09;&#xff0c;而 Hive 兩者都不完全符合。如果操作兩個數據源都是mysql或者和關系數…

2025年上海市星光計劃第十一屆職業院校技能大賽高職組“信息安全管理與評估”賽項交換部分前6題詳解(僅供參考)

1.北京總公司和南京分公司有兩條裸纖采用了骨干鏈路配置,做必要的配置,只允許必要的Vlan 通過,不允許其他 Vlan 信息通過包含 Vlan1,禁止使用 trunk鏈路。 骨干鏈路位置??:總公司 SW 與分公司 AC 之間的兩條物理鏈路(Ethernet 1/0/5-6 必要 VLAN??: ?總公司:Vlan…

學習nginx location ~ .*.(js|css)?$語法規則

引言 nginx作為一款高性能的Web服務和反向代理服務&#xff0c;在網站性能優化中扮演著重要的角色。其中&#xff0c;location指令的正確配置是優化工作的關鍵之一。 這篇記錄主要解析location ~ .*\.(js|css)?$這一特定的語法規則&#xff0c;幫助大家理解其在nginx配置中的…

Nmap網絡掃描工具詳細使用教程

目錄 Nmap 主要功能 網絡存活主機發現 (ARP Ping Scan) 綜合信息收集掃描 (Stealth SYN Service OS) 全端口掃描 (Full Port Scan) NSE 漏洞腳本掃描 SMB 信息枚舉 HTTP 服務深度枚舉 SSH 安全審計 隱蔽掃描與防火墻規避 Nmap 主要功能 Nmap 主要有以下幾個核心功能…

Spring Boot 3.x 的 @EnableAsync應用實例

語法結構使用 EnableAsync 其實就像為你的應用穿上一件時尚的外套&#xff0c;簡單又高效&#xff01;只需在你的配置類上添加這個注解&#xff0c;輕松開啟異步之旅。代碼如下&#xff1a;想象一下&#xff0c;你的應用一瞬間變得靈活無比&#xff0c;像一個跳舞的機器人&…

Nginx Tomcat Jar包開機啟動自動配置

一、Nginx配置1、創建systemd nginx 服務文件vi /usr/lib/systemd/system/nginx.service### 內容[Unit] DescriptionThe nginx HTTP and reverse proxy server Afternetwork.target[Service] Typeforking ExecStartPre/mnt/nginx/sbin/nginx -t ExecStart/mnt/nginx/sbin/nginx…

修訂版!Uniapp從Vue3編譯到安卓環境踩坑記錄

Uniapp從Vue3編譯到安卓環境踩坑記錄 在使用Uniapp開發Vue3項目并編譯到安卓環境時&#xff0c;我遇到了不少問題&#xff0c;現將主要踩坑點及解決方案整理如下&#xff0c;供大家參考。 1. 動態導入與靜態導入問題 問題描述&#xff1a; 在Vue3項目中使用的動態導入語法在Uni…

零售消費企業的數字化增長實踐,2025新版下載

當下零售消費行業&#xff0c;早不是有貨就好賣的時代了。一方面&#xff0c;前兩年消費市場的熱度催生出大批新品牌入場&#xff0c;供給端瞬間擁擠&#xff1b;另一方面&#xff0c;消費者獲取信息越來越容易&#xff0c;新潮流、新觀念幾天一個變化。企業想穩住增長、必須要…

[網鼎杯 2020 青龍組]AreUSerialz

BUUCTF在線評測BUUCTF 是一個 CTF 競賽和訓練平臺&#xff0c;為各位 CTF 選手提供真實賽題在線復現等服務。https://buuoj.cn/challenges#[%E7%BD%91%E9%BC%8E%E6%9D%AF%202020%20%E9%9D%92%E9%BE%99%E7%BB%84]AreUSerialz啟動靶機&#xff0c;頁面顯示php代碼 <?phpincl…