You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python手势识别石头剪刀布游戏平局计数器异常问题求助

问题解决:石头剪刀布游戏平局计数器异常递增

问题现象

使用Python结合OpenCV、MediaPipe开发的石头剪刀布游戏中,平局计数器dcounter无法正常累加:1次平局后显示79,2次平局后显示158,每次平局实际被累加了近80次,而非预期的1次。

错误原因

代码中计数逻辑放在了clock < 200的分支内,该分支对应游戏结果展示阶段(从clock=120到clock=199,共80帧)。每经过一帧,代码就会执行一次平局判断并累加计数器,导致一次平局被重复计数80次。

修复方案

将胜负及平局的计数逻辑移至clock == 120的分支中——这是游戏结果唯一确定的时刻,仅会执行一次,确保每次游戏结果只触发一次计数:

  • 在clock == 120获取到双方手势后,立即判断胜负关系并更新计数器
  • 将结果文本的拼接逻辑保留在clock < 200分支中,负责展示结果

修复后的完整代码

import cv2 as cv
import mediapipe as mp

username1 = input("Enter username:")
username2 = input("Enter username:")

mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_hands = mp.solutions.hands

# 判断手势是剪刀、石头还是布
def getHandMove(hand_landmarks):
    landmarks = hand_landmarks.landmark
    if all([landmarks[i].y < landmarks[i+3].y for i in range(9,20,4)]):return "steen"
    elif landmarks[13].y < landmarks[16].y and landmarks[17].y < landmarks[20].y:return "schaar"
    else: return "papier"

# 连接摄像头
vid = cv.VideoCapture(0)

# 游戏时钟
clock = 0
p1_move = p2_move = None
gameText = ""
success = True

# 胜利计数器
wcounter = 0

# 失败计数器
lcounter = 0

# 平局计数器
dcounter = 0

# 初始化手部追踪模型
with mp_hands.Hands(model_complexity=0,
                    min_detection_confidence=0.5,   
                    min_tracking_confidence=0.5) as hands:
    while True:
        ret, frame = vid.read()
        if not ret or frame is None: break
        frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
        
        results = hands.process(frame,)
        
        frame = cv.cvtColor(frame, cv.COLOR_RGB2BGR)
        if results.multi_hand_landmarks:
            for hand_landsmarks in results.multi_hand_landmarks:
                mp_drawing.draw_landmarks(frame, 
                                          hand_landsmarks,
                                          mp_hands.HAND_CONNECTIONS,
                                          mp_drawing_styles.get_default_hand_landmarks_style(),
                                          mp_drawing_styles.get_default_hand_connections_style())
                
        # 游戏流程控制
        if 0 <= clock < 60:
            success = True
            gameText = "Ready?"
        elif clock < 80: gameText = "schaar"
        elif clock < 100: gameText = "steen"
        elif clock < 120: gameText = "papier"
        elif clock == 120: 
            # 获取手部手势结果
            hls = results.multi_hand_landmarks
            if hls and len(hls) == 2:
                p1_move = getHandMove(hls[0])
                p2_move = getHandMove(hls[1])
                # 在此处判断胜负并更新计数器(仅执行一次)
                if p1_move == p2_move:
                    dcounter += 1
                elif (p1_move == "papier" and p2_move == "steen") or \
                     (p1_move == "steen" and p2_move == "schaar") or \
                     (p1_move == "schaar" and p2_move == "papier"):
                    wcounter += 1
                else:
                    lcounter += 1
            else: 
                success = False
        elif clock < 200:
            if success:
                # 展示游戏结果文本
                gameText = f"{username1} koos voor {p1_move}. {username2} koos voor {p2_move}."
                if p1_move == p2_move: 
                    gameText = f"{gameText} gelijkspel!"
                elif (p1_move == "papier" and p2_move == "steen") or \
                     (p1_move == "steen" and p2_move == "schaar") or \
                     (p1_move == "schaar" and p2_move == "papier"):
                    gameText = f"{gameText} {username1} wint!"
                else: 
                    gameText = f"{gameText} {username2} wint!"
            else:
                gameText = "Ongeldig"
                
        # 在帧上绘制文本
        cv.putText(frame, f"Clock: {clock}", (50,50), cv.FONT_HERSHEY_PLAIN, 2, (0,255,255), 2, cv.LINE_AA)
        cv.putText(frame, gameText, (50,80), cv.FONT_HERSHEY_PLAIN, 1, (0,255,255), 2, cv.LINE_AA)
        clock = (clock + 1) % 200
        
        # 翻转画面,使玩家位置符合直觉
        cv.flip(frame, 1)
        
        # 显示帧
        cv.imshow('frame', frame)
        
        # 按q键退出游戏
        if cv.waitKey(1) & 0xFF == ord('q'): break
    
vid.release()
cv.destroyAllWindows()

print(f"胜利次数: {wcounter}, 失败次数: {lcounter}, 平局次数: {dcounter}")

内容的提问来源于stack exchange,提问作者Stef Verniers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 04:06:26