訂閱
糾錯(cuò)
加入自媒體

在 Python 中使用 OpenCV 構(gòu)建 Color Catcher 游戲

介紹

你是否曾經(jīng)想在 Python 中使用 OpenCV 創(chuàng)建自己的游戲?

今天我們將構(gòu)建一個(gè)名為 Color Catcher 的游戲,該游戲挑戰(zhàn)玩家使用手部跟蹤機(jī)制接住從屏幕頂部掉落的彩球。

設(shè)置游戲窗口

構(gòu)建游戲的第一步是使用 OpenCV 設(shè)置游戲窗口。我們將定義窗口大小、創(chuàng)建窗口并設(shè)置其在屏幕上的位置:

# Set up the game window

window_size = (640, 480)

window_name = 'Color Catcher'

cv2.namedWindow(window_name)

cv2.moveWindow(window_name, 0, 0)

定義游戲?qū)ο?/p>

接下來(lái),我們將定義游戲?qū)ο蟆T?Color Catcher 中,我們有兩個(gè)主要的游戲?qū)ο螅翰妒趾颓颉?/p>

捕手是玩家用手移動(dòng)的矩形,而球是從屏幕頂部落下的隨機(jī)生成的圓圈。我們將定義這些游戲?qū)ο蟮膶傩裕?/p>

# Set up the game objects

catcher_color = (0, 0, 255)

catcher_width = 100

catcher_height = 20

catcher_position = np.array([window_size[0]//2, window_size[1]-catcher_height], dtype=int)

catcher_velocity = np.array([10, 0], dtype=int)

ball_radius = 20

ball_speed = 5

ball_colors = [(0, 255, 0), (255, 0, 0), (0, 0, 255)]

balls = []

score = 0

從網(wǎng)絡(luò)攝像頭捕獲視頻

為了跟蹤玩家的手部動(dòng)作,我們需要使用 OpenCV 從網(wǎng)絡(luò)攝像頭捕獲視頻。

我們將創(chuàng)建一個(gè)視頻捕獲設(shè)備并循環(huán)播放視頻的每一幀:

# Set up the video capture device

cap = cv2.VideoCapture(0)

while True:

    # Read a frame from the video capture device

    ret, frame = cap.read()

    if not ret:

        break

檢測(cè)玩家的手

為了跟蹤玩家的手部動(dòng)作,我們將使用 OpenCV 的輪廓檢測(cè)功能。首先,我們將每個(gè)幀轉(zhuǎn)換為灰度并應(yīng)用閾值以便更容易檢測(cè)輪廓:

# Convert the frame to grayscale and apply a threshold

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

接下來(lái),我們將在閾值圖像中找到輪廓,并確定面積最大的輪廓,這應(yīng)該是玩家的手:

# Find the contours in the thresholded image

contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Find the contour with the largest area, which should be the hand

if contours:

    hand_contour = max(contours, key=cv2.contourArea)

    hand_hull = cv2.convexHull(hand_contour)

    hand_center = np.mean(hand_contour, axis=0, dtype=int)[0]

移動(dòng)捕手

一旦我們檢測(cè)到玩家手的位置,我們就可以相應(yīng)地移動(dòng)捕手。

在代碼中,我們檢查手中心的 x 坐標(biāo)并將其與接球手位置的 x 坐標(biāo)進(jìn)行比較。如果手在接球手的左側(cè),我們通過(guò)從接球手的當(dāng)前位置減去接球手的速度,將接球手向左移動(dòng)。如果手在捕手的右側(cè),我們通過(guò)將捕手的速度添加到其當(dāng)前位置來(lái)將捕手移動(dòng)到右側(cè)。

    if hand_center[0] < catcher_position[0] and catcher_position[0] > 0:

        catcher_position -= catcher_velocity

    elif hand_center[0] > catcher_position[0]+catcher_width and catcher_position[0]+catcher_width < window_size[0]:

        catcher_position += catcher_velocity

生成和移動(dòng)球:

如果當(dāng)前比賽中的球數(shù)少于五個(gè),我們將生成具有隨機(jī)顏色和位置的新球。我們將包含球的顏色、位置和速度的元組附加到balls列表中。

    if len(balls) < 5:

        ball_color = random.choice(ball_colors)

        ball_position = np.array([random.randint(ball_radius, window_size[0]-ball_radius), 0], dtype=int)

        ball_velocity = np.array([0, ball_speed], dtype=int)

        balls.append((ball_color, ball_position, ball_velocity))

然后我們遍歷balls列表中的每個(gè)球,通過(guò)將其速度添加到其當(dāng)前位置來(lái)更新其位置,并檢查它是否與接球手發(fā)生碰撞或擊中游戲窗口的底部。

如果球與接球手發(fā)生碰撞,我們將其從balls列表中移除,增加玩家的得分,然后跳出循環(huán)。

如果球擊中了游戲窗口的底部,我們將其從balls列表中移除并跳出循環(huán)。

    for i in range(len(balls)):

        balls[i] = (balls[i][0], balls[i][1]+balls[i][2], balls[i][2])

        ball_position = balls[i][1]

        if ball_position[1]+ball_radius >= catcher_position[1] and 

           ball_position[0] >= catcher_position[0] and 

           ball_position[0] <= catcher_position[0]+catcher_width:

            balls.pop(i)

            score += 1

            break

        elif ball_position[1]+ball_radius >= window_size[1]:

            balls.pop(i)

            break

繪制游戲?qū)ο螅?/strong>

最后,我們使用cv2.rectangle()和cv2.circle()函數(shù)在框架上繪制游戲?qū)ο蟆N覀兪褂胣p.zeros()創(chuàng)建一個(gè)黑色框架,將捕手繪制為紅色矩形,并將每個(gè)球繪制為彩色圓圈。

我們還使用cv2.putText()函數(shù)在框架的左上角顯示玩家的分?jǐn)?shù)。

    frame = np.zeros(window_size+(3,), dtype=np.uint8)

    cv2.rectangle(frame, tuple(catcher_position), tuple(catcher_position+np.array([catcher_width, catcher_height])), catcher_color, -1)

    for ball in balls:

        cv2.circle(frame, tuple(ball[1]), ball_radius, ball[0], -1)

    

    cv2.putText(frame, "Score: {}".format(score), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)

    cv2.imshow(window_name, frame)

退出游戲:

最后,游戲循環(huán)包含在while循環(huán)中。在這個(gè)循環(huán)中,執(zhí)行以下任務(wù):

使用cap.read()方法從視頻捕獲設(shè)備讀取新幀。處理框架以檢測(cè)手區(qū)域并相應(yīng)地移動(dòng)捕手。如有必要,將生成一個(gè)具有隨機(jī)顏色和位置的新球。球被移動(dòng)并檢查是否與接球手發(fā)生碰撞。游戲?qū)ο罄L制在框架上。框架顯示在屏幕上。循環(huán)繼續(xù),直到用戶按下“q”鍵。

按“q”鍵可以退出游戲。這是使用cv2.waitKey()方法完成的,該方法等待鍵盤(pán)事件的給定毫秒數(shù)。如果按鍵被按下,該方法返回按鍵的 ASCII 代碼,如果沒(méi)有按鍵被按下,則返回 -1。

我們使用按位與運(yùn)算符 ( &) 提取結(jié)果的最低有效 8 位,這為我們提供了按 256 模的按下鍵的 ASCII 代碼。我們將此值與 'q' 鍵 ( ord('q')) 的 ASCII 代碼進(jìn)行比較,如果匹配則退出循環(huán)。

# Exit the game if the user presses the 'q' key

if cv2.waitKey(1) & 0xFF == ord('q'):

    break

退出循環(huán)后,我們分別使用cap.release()和cv2.destroyAllWindows()方法釋放視頻捕獲設(shè)備并關(guān)閉游戲窗口。

# Release the video capture device and close the game window

cap.release()

cv2.destroyAllWindows()

就是這樣!你現(xiàn)在應(yīng)該能夠運(yùn)行代碼并玩游戲了。這個(gè)游戲是一個(gè)簡(jiǎn)單的例子,說(shuō)明了如何使用計(jì)算機(jī)視覺(jué)來(lái)實(shí)時(shí)控制游戲?qū)ο蟮囊苿?dòng)。當(dāng)然,還有很大的改進(jìn)和優(yōu)化空間,但這應(yīng)該足以讓你入門(mén)。

編碼愉快!

完整代碼:

https://github.com/Yaga987/Computer-Vision/blob/main/CompVisGame.py

       原文標(biāo)題 : 在 Python 中使用 OpenCV 構(gòu)建 Color Catcher 游戲

聲明: 本文由入駐維科號(hào)的作者撰寫(xiě),觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號(hào)
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯(cuò)
x
*文字標(biāo)題:
*糾錯(cuò)內(nèi)容:
聯(lián)系郵箱:
*驗(yàn) 證 碼:

粵公網(wǎng)安備 44030502002758號(hào)