中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用Python制作一個桌上冰球視覺小游戲

發布時間:2023-05-09 10:51:04 來源:億速云 閱讀:133 作者:zzz 欄目:編程語言

這篇文章主要介紹“怎么用Python制作一個桌上冰球視覺小游戲”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“怎么用Python制作一個桌上冰球視覺小游戲”文章能幫助大家解決問題。

1. 文件配置

1.1 導入工具包
pip install opencv_python==4.2.0.34  # 安裝opencv
pip install mediapipe  # 安裝mediapipe
# pip install mediapipe --user  #有user報錯的話試試這個
pip install cvzone  # 安裝cvzone
 
# 導入工具包
import cv2
import cvzone
from cvzone.HandTrackingModule import HandDetector  # 導入手部檢測模塊

21個手部關鍵點坐標如下:

怎么用Python制作一個桌上冰球視覺小游戲

1.2 素材圖片準備

開始之前,先準備球桌的圖片,球的圖片,球拍的圖片。我是用PPT畫的圖,球和球拍的圖片一定要保存成 .png 格式的。放在同一個文件夾中以備讀取。

怎么用Python制作一個桌上冰球視覺小游戲

2. 手部關鍵點檢測、素材導入

2.1 方法介紹

(1) cvzone.HandTrackingModule.HandDetector()手部關鍵點檢測方法

參數:

mode: 默認為 False,將輸入圖像視為視頻流。它將嘗試在第一個輸入圖像中檢測手,并在成功檢測后進一步定位手的坐標。在隨后的圖像中,一旦檢測到所有 maxHands 手并定位了相應的手的坐標,它就會跟蹤這些坐標,而不會調用另一個檢測,直到它失去對任何一只手的跟蹤。這減少了延遲,非常適合處理視頻幀。如果設置為 True,則在每個輸入圖像上運行手部檢測,用于處理一批靜態的、可能不相關的圖像。

maxHands: 最多檢測幾只手,默認為 2

detectionCon: 手部檢測模型的最小置信值(0-1之間),超過閾值則檢測成功。默認為 0.5

minTrackingCon: 坐標跟蹤模型的最小置信值 (0-1之間),用于將手部坐標視為成功跟蹤,不成功則在下一個輸入圖像上自動調用手部檢測。將其設置為更高的值可以提高解決方案的穩健性,但代價是更高的延遲。如果 mode 為 True,則忽略這個參數,手部檢測將在每個圖像上運行。默認為 0.5

它的參數和返回值類似于官方函數 mediapipe.solutions.hands.Hands()

MULTI_HAND_LANDMARKS: 被檢測/跟蹤的手的集合,其中每只手被表示為21個手部地標的列表,每個地標由x, y, z組成。

MULTI_HANDEDNESS: 被檢測/追蹤的手是左手還是右手的集合。每只手由label(標簽)和score(分數)組成。 label 是 'Left' 或 'Right' 值的字符串。 score 是預測左右手的估計概率。

(2)cvzone.HandTrackingModule.HandDetector.findHands() 找到手部關鍵點并繪圖

參數:

img: 需要檢測關鍵點的幀圖像,格式為BGR

draw: 是否需要在原圖像上繪制關鍵點及識別框

flipType: 圖像是否需要翻轉,當視頻圖像和我們自己不是鏡像關系時,設為True就可以了

返回值:

hands: 檢測到的手部信息,由0或1或2個字典組成的列表。如果檢測到兩只手就是由兩個字典組成的列表。字典中包含:21個關鍵點坐標(x,y,z),檢測框左上坐標及其寬高,檢測框中心點坐標,檢測出是哪一只手。

img: 返回繪制了關鍵點及連線后的圖像

(3)cv2.addWeighted()圖像融合

將兩張圖像按一定比例融合在一起,需要兩張圖像的size和通道數相同

兩張圖像按一定比例融合: cv2.addWeighted(圖像1, 權重1, 圖像2, 權重2, 亮度偏置)

相當于 y = a x1 + b x2 + c,其中 a、b 代表權重,c 代表亮度上提亮多少

2.2 代碼展示

首先 cv2.imread() 中的參數 cv2.IMREAD_UNCHANGED 是指用圖片的原來格式打開,包含Alpha通道。即以不改變圖片的方式打開,圖片是彩色那么讀進來就是彩色,圖片是灰度圖那么讀進來就是灰度圖,讀進來的圖片的shape如下:

怎么用Python制作一個桌上冰球視覺小游戲

該部分代碼主要負責手部關鍵點檢測,融合背景圖像和視頻幀圖像

import cv2
import cvzone
from cvzone.HandTrackingModule import HandDetector  # 導入手部檢測模塊
 
#(1)捕獲攝像頭
cap = cv2.VideoCapture(0)  # 0代表電腦自帶的攝像頭
cap.set(3, 1280)  # 讀入的圖像的寬
cap.set(4, 720)   # 讀入的圖像的高
 
 
#(2)文件配置
# 導入所有需要對圖片文件
imgDesk = cv2.imread('games/desk.jpg')  # 球桌的圖片
imgBall = cv2.imread('games/ball.png', cv2.IMREAD_UNCHANGED)  # 球的圖片
imgBlock1 = cv2.imread('games/block1', cv2.IMREAD_UNCHANGED)  # 球拍的圖片
imgBlock2 = cv2.imread('games/block2', cv2.IMREAD_UNCHANGED)  # 球拍的圖片
# 調整球桌圖片的size
imgDesk = cv2.resize(imgDesk, dsize=(1280,720))
 
 
#(3)參數設置
# 接收手部關鍵點識別的方法,最小手部檢測模塊置信度0.8,最多檢測2只手
detector = HandDetector(detectionCon=0.8, maxHands=2)
 
 
#(4)處理幀圖像
while True:
 
    # 返回是否讀取成功,以及讀取后的幀圖像
    success, img = cap.read()  # 每次執行讀取一幀
    
    # 圖片翻轉呈鏡像關系,1代表左右翻轉,0代表上下翻轉
    img = cv2.flip(img, flipCode=1)
    
    # 手部關鍵點檢測,返回每個只手的信息和繪制后的圖像
    hands, img = detector.findHands(img, flipType=False)  # 上面翻轉過了這里就不用翻轉了
 
    # 將球桌圖片和視頻幀圖像融合在一起, 兩張圖的shape要相同
    # 給出每張圖片的融合權重, 亮度偏置為0,這樣就變成了半透明的顯示形式
    img = cv2.addWeighted(img, 0.3, imgDesk, 0.7, 0)
 
    
    #(5)添加桌球的圖片,將imgBall放在球桌img的指定坐標位置
    img = cvzone.overlayPNG(img, imgBall, (100,100))
    
    # 圖像展示
    cv2.imshow('img', img)
    # 每幀滯留1ms后消失
    k = cv2.waitKey(1)
    # ESC鍵退出程序
    if k & 0XFF==27:
        break
 
# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()

3. 關鍵點處理、球拍移動

3.1 方法介紹

這部分主要完成兩項工作,第一是左右手分別控制左側和右側的球拍,第二個是球以一定的速度移動。

(1)控制球拍

hand['bbox'] 中包含了手部檢測框的左上角坐標和檢測框的寬高,使用手掌中心點的 y 坐標來控制球拍的上下移動。由于兩個球拍的shape是相同的,因此只要獲取一個球拍的高度 h3 即可。使用掌心中點 y 坐標控制球拍中點的 y1 坐標,公式為:y1 = (y + h) // 2 - h3 // 2

接著使用 cvzone.overlayPNG() 就可以將球拍圖片覆蓋在原圖片的指定區域,其中坐標參數是指覆蓋區域的左上角坐標。固定橫坐標,只上下移動。

(2)球移動

首先要規定球的移動速度 speedx, speedy = 10, 10 代表球每一幀沿x軸正方向移動10個像素,沿y軸正方向移動10個像素,那么球的初始合速度方向是沿圖片的正右下角移動

如果球碰撞到了球桌的上下邊框,就反彈。speedy = -speedy。代表x方向每幀移動的步長不變,y方向每幀移動的方向反轉,即入射角等于出射角。

3.2 代碼展示

在上述代碼中補充

import cv2
import cvzone
import numpy as np
from cvzone.HandTrackingModule import HandDetector  # 導入手部檢測模塊
 
#(1)捕獲攝像頭
cap = cv2.VideoCapture(0)  # 0代表電腦自帶的攝像頭
cap.set(3, 1280)  # 讀入的圖像的寬
cap.set(4, 720)   # 讀入的圖像的高
 
 
#(2)文件配置
# 導入所有需要對圖片文件
imgDesk = cv2.imread('games/desk.jpg')  # 球桌的圖片
imgBall = cv2.imread('games/ball.png', cv2.IMREAD_UNCHANGED)  # 球的圖片
imgBlock1 = cv2.imread('games/block1.png', cv2.IMREAD_UNCHANGED)  # 球拍的圖片
imgBlock2 = cv2.imread('games/block2.png', cv2.IMREAD_UNCHANGED)  # 球拍的圖片
# 調整球桌圖片的size
imgDesk = cv2.resize(imgDesk, dsize=(1280,720))
# 調整球拍的size
imgBlock1 = cv2.resize(imgBlock1, dsize=(50,200))
imgBlock2 = cv2.resize(imgBlock2, dsize=(50,200))
 
 
#(3)參數設置
# 接收手部關鍵點識別的方法,最小手部檢測模塊置信度0.8,最多檢測2只手
detector = HandDetector(detectionCon=0.8, maxHands=2)
 
# 球的默認位置
ballpos = [100, 100]
 
# 球的移動速度,每幀15個像素
speedx, speedy = 10, 10
 
 
#(4)處理幀圖像
while True:
 
    # 返回是否讀取成功,以及讀取后的幀圖像
    success, img = cap.read()  # 每次執行讀取一幀
    
    # 圖片翻轉呈鏡像關系,1代表左右翻轉,0代表上下翻轉
    img = cv2.flip(img, flipCode=1)
    
    # 手部關鍵點檢測,返回每個只手的信息和繪制后的圖像
    hands, img = detector.findHands(img, flipType=False)  # 上面翻轉過了這里就不用翻轉了
 
    # 將球桌圖片和視頻幀圖像融合在一起, 兩張圖的shape要相同
    # 給出每張圖片的融合權重, 亮度偏置為0,這樣就變成了半透明的顯示形式
    img = cv2.addWeighted(img, 0.4, imgDesk, 0.6, 0)
    
    
    #(5)處理手部關鍵點,如果檢測到手了就進行下一步
    if hands:
        
        # 遍歷每檢測的2只手,獲取每一只手的坐標
        for hand in hands:
            
            # 獲取手部檢測框的左上坐標xy,寬高wh
            x, y, w, h = hand['bbox']
            
            # 獲取球拍的寬高
            h3, w1 = imgBlock1.shape[0:2]
            
            # 球拍的中心y坐標,隨著掌心移動
            y1 = (y + h) // 2 - h3 // 2
 
            # 如果檢測到了左手
            if hand['type'] == 'Left':
                
                # 左側的球拍x軸固定,y坐標隨左手掌間中點移動
                img = cvzone.overlayPNG(img, imgBlock1, (55,y1))
                
            # 如果檢測到了右手
            if hand['type'] == 'Right':
                
                # 右側的球拍x軸固定,y坐標隨右手掌間中點移動
                img = cvzone.overlayPNG(img, imgBlock2, (1280-55,y1))
                      
    #(6)改變球的位置
    # 如果球的y坐標在超出了桌面的上或下邊框范圍,調整移動方向
    if ballpos[1] >= 600 or ballpos[1] <= 50:
        
        # y方向的速度調整為反方向,那么x方向和y方向的合速度方向調整了
        speedy = -speedy
 
    ballpos[0] = ballpos[0] + speedx  # 調整球的x坐標
    ballpos[1] = ballpos[1] + speedy  # 調整球的y坐標
 
    
    #(5)添加桌球的圖片,將imgBall放在球桌img的指定坐標位置
    img = cvzone.overlayPNG(img, imgBall, ballpos)
    
    # 圖像展示
    cv2.imshow('img', img)
    # 每幀滯留1ms后消失
    k = cv2.waitKey(1)
    # ESC鍵退出程序
    if k & 0XFF==27:
        break
 
# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()

4. 球拍擊球、游戲完善

4.1 方法介紹

這一部分主要完成三項工作,第一是球拍擊打到球,球需要反彈;第二是如果球進入黃色區域,游戲結束;第三是左右側擊球得分計數器。

(1)球拍擊球

看到代碼中的第(5)步,ballpos 代表球的左上角坐標(x,y),100 < ballpos[0] < 100+w1 代表球到了球拍橫坐標區域范圍內部了,y1 < ballpos[1] < y1+h3 代表球的y坐標在球拍y坐標內部,這時表明擊球成功,speedx = -speedx 只改變沿x軸的速度方向,不改變沿y軸的速度方向。

(2)球進黃區,游戲結束

if ballpos[0] < 50 or ballpos[0] > 1150,如果球圖片的左上坐標的 x 坐標,在黃區邊緣,整個程序退出。當然也可以做一個游戲結束界面,我之前的博文里也有介紹,我偷個懶不寫了。

(3)計數器

首先定義個變量初始化記錄左右側的擊球次數 score = [0, 0],如果有一側的球拍擊中球,那么對應該側計數加一。

4.2 代碼展示

上面代碼是掌心控制球拍,這里改成食指指尖控制球拍中點移動。

import cv2
import cvzone
from cvzone.HandTrackingModule import HandDetector  # 導入手部檢測模塊
 
#(1)捕獲攝像頭
cap = cv2.VideoCapture(0)  # 0代表電腦自帶的攝像頭
cap.set(3, 1280)  # 讀入的圖像的寬
cap.set(4, 720)   # 讀入的圖像的高
 
 
#(2)文件配置
# 導入所有需要對圖片文件
imgDesk = cv2.imread('games/desk.jpg')  # 球桌的圖片
imgBall = cv2.imread('games/ball.png', cv2.IMREAD_UNCHANGED)  # 球的圖片
imgBlock1 = cv2.imread('games/block1.png', cv2.IMREAD_UNCHANGED)  # 球拍的圖片
imgBlock2 = cv2.imread('games/block2.png', cv2.IMREAD_UNCHANGED)  # 球拍的圖片
# 調整球桌圖片的size
imgDesk = cv2.resize(imgDesk, dsize=(1280,720))
# 調整球拍的size
imgBlock1 = cv2.resize(imgBlock1, dsize=(50,200))
imgBlock2 = cv2.resize(imgBlock2, dsize=(50,200))
 
 
#(3)參數設置
# 接收手部關鍵點識別的方法,最小手部檢測模塊置信度0.8,最多檢測2只手
detector = HandDetector(detectionCon=0.8, maxHands=2)
 
# 球的默認位置
ballpos = [100, 100]
 
# 球的移動速度,每幀15個像素
speedx, speedy = 10, 10
 
# 記錄是否游戲結束
gameover = False
 
# 記錄左右的擊球數
score = [0, 0]
 
 
#(4)處理幀圖像
while True:
 
    # 返回是否讀取成功,以及讀取后的幀圖像
    success, img = cap.read()  # 每次執行讀取一幀
    
    # 圖片翻轉呈鏡像關系,1代表左右翻轉,0代表上下翻轉
    img = cv2.flip(img, flipCode=1)
    
    # 手部關鍵點檢測,返回每個只手的信息和繪制后的圖像
    hands, img = detector.findHands(img, flipType=False)  # 上面翻轉過了這里就不用翻轉了
 
    # 將球桌圖片和視頻幀圖像融合在一起, 兩張圖的shape要相同
    # 給出每張圖片的融合權重, 亮度偏置為0,這樣就變成了半透明的顯示形式
    img = cv2.addWeighted(img, 0.4, imgDesk, 0.6, 0)
    
    
    #(5)處理手部關鍵點,如果檢測到手了就進行下一步
    if hands:
        
        # 遍歷每檢測的2只手,獲取每一只手的坐標
        for hand in hands:
            
            # 獲取食指坐標(x,y,z)
            x, y, z = hand['lmList'][8]
            
            # 獲取球拍的寬高
            h3, w1 = imgBlock1.shape[0:2]
            
            # 球拍的中心y坐標,隨著掌心移動
            y1 = y - h3 // 2
 
            # 如果檢測到了左手
            if hand['type'] == 'Left':
                
                # 左側的球拍x軸固定,y坐標隨左手掌間中點移動
                img = cvzone.overlayPNG(img, imgBlock1, (100,y1))
                
                # 檢查球是否被左球拍擊中, 球的xy坐標是否在球拍xy坐標附近
                if 100 < ballpos[0] < 100+w1 and y1 < ballpos[1] < y1+h3:
                    
                    # 滿足條件代表球拍擊中了,改變球的移動方向
                    speedx = -speedx  # x方向設為反方向
                    
                    # 得分加一
                    score[0] += 1
                
                
            # 如果檢測到了右手
            if hand['type'] == 'Right':
                
                # 右側的球拍x軸固定,y坐標隨右手掌間中點移動
                img = cvzone.overlayPNG(img, imgBlock2, (1150,y1))
                
                # 檢查球是否被右球拍擊中
                if 1050 < ballpos[0] < 1050+w1 and y1 < ballpos[1] < y1+h3:
                    
                    # 滿足條件代表球拍擊中了,改變球的移動方向
                    speedx = -speedx  # x方向設為反方向
                    
                    # 得分加一
                    score[1] += 1
 
 
    #(6)檢查球是否沒接到,那么游戲結束
    if ballpos[0] < 50 or ballpos[0] > 1150:
        gameover = True
    
    # 游戲結束,畫面就不動了
    if gameover is True:
        break
     
    # 游戲沒結束就接下去執行
    else:
         #(7)調整球的坐標
         # 如果球的y坐標在超出了桌面的上或下邊框范圍,調整移動方向
         if ballpos[1] >= 600 or ballpos[1] <= 50:
             
             # y方向的速度調整為反方向,那么x方向和y方向的合速度方向調整了
             speedy = -speedy
         
         # 每一整都調整xy坐標
         ballpos[0] = ballpos[0] + speedx  # 調整球的x坐標
         ballpos[1] = ballpos[1] + speedy  # 調整球的y坐標
    
         #(8)添加桌球的圖片,將imgBall放在球桌img的指定坐標位置
         img = cvzone.overlayPNG(img, imgBall, ballpos)
    
    
    #(9)顯示記分板
    cvzone.putTextRect(img, f'Left:{score[0]} and Right:{score[1]}', (400,710))
 
    #(10)圖像展示
    cv2.imshow('img', img)
    # 每幀滯留1ms后消失
    k = cv2.waitKey(1)
    # ESC鍵退出程序
    if k & 0XFF==27:
        break
 
# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()

關于“怎么用Python制作一個桌上冰球視覺小游戲”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

海盐县| 来安县| 石河子市| 湘阴县| 施甸县| 漳浦县| 山西省| 江口县| 洞头县| 保康县| 湟源县| 泗水县| 阳西县| 曲沃县| 托克逊县| 金华市| 澳门| 扎囊县| 新巴尔虎右旗| 资源县| 江门市| 大余县| 平利县| 蓝田县| 健康| 南溪县| 石门县| 凤凰县| 宜丰县| 焉耆| 女性| 井研县| 迁西县| 崇阳县| 广平县| 潮州市| 陇川县| 泽州县| 株洲县| 洱源县| 迁安市|