成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Python如何利用手勢(shì)識(shí)別實(shí)現(xiàn)貪吃蛇游戲

本文小編為大家詳細(xì)介紹“Python如何利用手勢(shì)識(shí)別實(shí)現(xiàn)貪吃蛇游戲”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Python如何利用手勢(shì)識(shí)別實(shí)現(xiàn)貪吃蛇游戲”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。

公司主營(yíng)業(yè)務(wù):網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)公司推出蕉嶺免費(fèi)做網(wǎng)站回饋大家。

    1、游戲的操作方式

    貪吃蛇游戲人盡皆知,計(jì)算機(jī)視覺鮮為人知,計(jì)算機(jī)視覺+貪吃蛇游戲會(huì)帶給人們更多的參與感以及新鮮度,本次這個(gè)項(xiàng)目就是主要使用手勢(shì)識(shí)別來完成貪吃蛇這個(gè)簡(jiǎn)單的游戲。在這個(gè)游戲中,電腦通過攝像頭捕捉到我們的手勢(shì)并判別是否進(jìn)行移動(dòng),玩家移動(dòng)手去操縱貪吃蛇得到屏幕中隨機(jī)出現(xiàn)的食物,每得到一個(gè)食物,就會(huì)算作一分,Score 就會(huì)加1并顯示在畫面中,當(dāng)玩家在操作的過程中不小心使得蛇的頭部和身體相撞,那么就會(huì)顯示GameOver! 按下 ‘r’ 鍵可以重新開始游戲。

    2、開發(fā)的過程中的注意事項(xiàng)

    (1) 圖像的左右問題

    由于我們是使用手勢(shì)來進(jìn)行控制蛇的移動(dòng)的,但攝像頭的畫面顯示的是別人的視角,所以這和玩家的左右意識(shí)剛好是相反的,因此我們要將攝像頭讀取到的畫面進(jìn)行一個(gè)左右的翻轉(zhuǎn)。原理上說就是將左右的像素點(diǎn)位置進(jìn)行一個(gè)調(diào)換,但在 Python 中可以使用一個(gè) cv2.flip( ) 函數(shù)就可以實(shí)現(xiàn)鏡像翻轉(zhuǎn)了。

    (2) 攝像頭的畫面尺寸問題

    過攝像頭得到的圖像我們需要在上面進(jìn)行游戲,因此畫面過小會(huì)導(dǎo)致游戲空間不足,在最開始可以對(duì)畫面的大小進(jìn)行一個(gè)預(yù)處理,設(shè)定一個(gè)較為合理的大小,最后得到的畫面玩游戲時(shí)才不會(huì)顯得局促。通過函數(shù) cap.set(3, m) cap.set(4, n) 可以實(shí)現(xiàn)對(duì)畫面的寬和高的設(shè)定。

    本項(xiàng)目中還會(huì)存在一些其他的注意事項(xiàng),比如判斷碰撞,判斷獲得食物等,我會(huì)在后面的項(xiàng)目過程中再加以介紹。

    三、游戲的實(shí)現(xiàn)要點(diǎn)

    1、選擇第三方庫

    一些使用到的第三方庫:

    import math
    import random
    import cvzone
    import cv2
    import numpy as np
    from cvzone.HandTrackingModule import HandDetector

    在本次項(xiàng)目中,我們主要使用到以上的幾個(gè)庫,其中使用 random 庫來隨機(jī)選擇像素點(diǎn)來放置食物甜甜圈,使用 cvzone 中的手部識(shí)別來進(jìn)行玩家手勢(shì)的檢測(cè),使用 cv2 來進(jìn)行一些基礎(chǔ)的圖像操作,其他的一些庫也各有用處,后面一一介紹。

    2、找到關(guān)鍵點(diǎn)并標(biāo)記

    在本次游戲中我們是選擇了一只手作為目標(biāo)節(jié)點(diǎn),所以當(dāng)我們檢測(cè)到畫面中出現(xiàn)手部時(shí)需要對(duì)其中的關(guān)鍵點(diǎn)進(jìn)行標(biāo)記,而這個(gè)關(guān)鍵點(diǎn)恰好是我們的貪吃蛇的頭部,由于我們是調(diào)用的第三方庫,而該庫可以對(duì)手部進(jìn)行3D的標(biāo)記,但我們只需要 x,y 兩個(gè)坐標(biāo)值就可以了,主要使用以下函數(shù)進(jìn)行手部關(guān)鍵節(jié)點(diǎn)的標(biāo)記:

    #檢測(cè)到第一個(gè)手,并標(biāo)記手部位置
        if hands:
            lmList = hands[0]['lmList']
            pointIndex = lmList[8][0:2] #第八個(gè)坐標(biāo)點(diǎn)的 x, y值,其中 z 值不被包括在里面
            cv2.circle(img, pointIndex, 20, (200, 0, 200), cv2.FILLED) #在關(guān)鍵點(diǎn)處繪制一個(gè)圓點(diǎn)并進(jìn)行填充(此處只是示范,后面會(huì)更改)
    3、創(chuàng)建一個(gè)類來保存關(guān)于游戲的所有功能

    我們需要實(shí)現(xiàn)的游戲是很多功能結(jié)合起來完成的,如果想要使用函數(shù)來實(shí)現(xiàn)這些功能,那么將會(huì)非常麻煩,當(dāng)我們使用 class 來完成時(shí),由于很多東西都保存在同一個(gè)類中,將會(huì)降低難度。在這個(gè) class 中我們將會(huì)創(chuàng)建很多重要的列表來存儲(chǔ)我們用得到的一些關(guān)鍵點(diǎn),比如貪吃蛇的身上的所有的點(diǎn)、貪吃蛇的長(zhǎng)度、蛇的總體距離、食物的放置、得分等:

    class SnakeGameClass:
        def __init__(self, pathFood):
            self.points = []  #貪吃蛇身上所有點(diǎn)
            self.lengths = []  #點(diǎn)與點(diǎn)之間的距離
            self.currentLength = 0  #當(dāng)下蛇的長(zhǎng)度
            self.allowedLength = 50  #最大允許長(zhǎng)度(閾值)
            self.previousHead = 0, 0  #手部關(guān)鍵點(diǎn)之后的第一個(gè)點(diǎn)
     
            self.imgFood = cv2.imread(pathFood, cv2.IMREAD_UNCHANGED) #定義食物
            self.hFood, self.wFood, _ = self.imgFood.shape
            self.foodPoint = 0, 0
            self.randomFoodLocation()
     
            self.score = 0
            self.gameOver = False
    4、定義函數(shù)進(jìn)行不斷更新

    隨著我們的手部的移動(dòng),貪吃蛇的長(zhǎng)度以及位置都會(huì)發(fā)生變化,所以我們需要?jiǎng)?chuàng)建一個(gè)函數(shù)來不斷進(jìn)行更新,滿足變化的需求(該部分也是在前面創(chuàng)建的大類里面完成的):

        def update(self, imgMain, currentHead):
            #游戲結(jié)束,打印文本
            if self.gameOver:
                cvzone.putTextRect(imgMain, "Game Over", [300, 400],
                                   scale=7, thickness=5, offset=20)
                cvzone.putTextRect(imgMain, f'Your Score: {self.score}', [300, 550],
                                   scale=7, thickness=5, offset=20)
            else:
                px, py = self.previousHead
                cx, cy = currentHead
     
                self.points.append([cx, cy])
                distance = math.hypot(cx - px, cy - py)
                self.lengths.append(distance)
                self.currentLength += distance
                self.previousHead = cx, cy
     
                #長(zhǎng)度縮小
                if self.currentLength > self.allowedLength:
                    for i, length in enumerate(self.lengths):
                        self.currentLength -= length
                        self.lengths.pop(i)
                        self.points.pop(i)
                        if self.currentLength < self.allowedLength:
                            break
     
                #檢查貪吃蛇是否已經(jīng)觸碰到食物
                rx, ry = self.foodPoint
                if rx - self.wFood // 2 < cx < rx + self.wFood // 2 and \
                        ry - self.hFood // 2 < cy < ry + self.hFood // 2:
                    self.randomFoodLocation()
                    self.allowedLength += 50
                    self.score += 1
                    print(self.score)
     
                #使用線條繪制貪吃蛇
                if self.points:
                    for i, point in enumerate(self.points):
                        if i != 0:
                            cv2.line(imgMain, self.points[i - 1], self.points[i], (0, 0, 255), 20)
                    cv2.circle(imgMain, self.points[-1], 20, (0, 255, 0), cv2.FILLED)
     
                #顯示食物
                imgMain = cvzone.overlayPNG(imgMain, self.imgFood,
                                            (rx - self.wFood // 2, ry - self.hFood // 2))
     
                cvzone.putTextRect(imgMain, f'Score: {self.score}', [50, 80],
                                   scale=3, thickness=3, offset=10)
     
                #檢測(cè)是否碰撞
                pts = np.array(self.points[:-2], np.int32)
                pts = pts.reshape((-1, 1, 2))
                cv2.polylines(imgMain, [pts], False, (0, 255, 0), 3)
                minDist = cv2.pointPolygonTest(pts, (cx, cy), True)
     
                if -1 <= minDist <= 1:
                    print("Hit")
                    self.gameOver = True
                    self.points = []  #蛇身上所有的點(diǎn)
                    self.lengths = []  #不同點(diǎn)之間的距離
                    self.currentLength = 0  #當(dāng)前蛇的長(zhǎng)度
                    self.allowedLength = 50  #最大允許長(zhǎng)度
                    self.previousHead = 0, 0  #先前的蛇的頭部
                    self.randomFoodLocation()
     
            return imgMain

    在這個(gè)更新的函數(shù)中,我們需要判斷很多東西,比如貪吃蛇是否觸碰到食物(如果觸碰到食物我們就要增加蛇的長(zhǎng)度并累積得分)、當(dāng)前長(zhǎng)度是否超過所允許的最大長(zhǎng)度(當(dāng)前長(zhǎng)度小于最大長(zhǎng)度就不必要進(jìn)行更改了,但如果當(dāng)前長(zhǎng)度大于最大長(zhǎng)度,則需要進(jìn)行縮短)、貪吃蛇是否發(fā)生碰撞(通過關(guān)鍵節(jié)點(diǎn)之間的距離判斷貪吃蛇是否發(fā)生了碰撞,如果發(fā)生了碰撞,則進(jìn)入 gameover 模塊,如果沒有,繼續(xù)游戲)等,都解釋在上面的代碼中了。

    主要是通過上面定義的 class 我們就能實(shí)現(xiàn)當(dāng)前的貪吃蛇游戲了。

    四、總體代碼

    本次小游戲我是在b站看到教程并一步步復(fù)現(xiàn)出來的,大家感興趣可以嘗試一下,當(dāng)然按照慣例整體代碼會(huì)貼在下面:

    """
    Author:XiaoMa
    CSDN Address:一馬歸一碼
    """
    import math
    import random
    import cvzone
    import cv2
    import numpy as np
    from cvzone.HandTrackingModule import HandDetector
     
    cap = cv2.VideoCapture(0)
     
    #設(shè)置畫面的尺寸大小,過小的話導(dǎo)致貪吃蛇活動(dòng)不開
    cap.set(3, 1280)
    cap.set(4, 720)
     
    detector = HandDetector(detectionCon=0.8, maxHands=1)
     
     
    class SnakeGameClass:
        def __init__(self, pathFood):
            self.points = []  #貪吃蛇身上所有點(diǎn)
            self.lengths = []  #每一個(gè)點(diǎn)之間的距離
            self.currentLength = 0  #當(dāng)下蛇的長(zhǎng)度
            self.allowedLength = 50  #最大允許長(zhǎng)度(閾值)
            self.previousHead = 0, 0  #手部關(guān)鍵點(diǎn)之后的第一個(gè)點(diǎn)
     
            self.imgFood = cv2.imread(pathFood, cv2.IMREAD_UNCHANGED) #定義食物
            self.hFood, self.wFood, _ = self.imgFood.shape
            self.foodPoint = 0, 0
            self.randomFoodLocation()
     
            self.score = 0
            self.gameOver = False
     
        def randomFoodLocation(self):
            self.foodPoint = random.randint(100, 1000), random.randint(100, 600)
     
        def update(self, imgMain, currentHead):
            #游戲結(jié)束,打印文本
            if self.gameOver:
                cvzone.putTextRect(imgMain, "Game Over", [300, 400],
                                   scale=7, thickness=5, offset=20)
                cvzone.putTextRect(imgMain, f'Your Score: {self.score}', [300, 550],
                                   scale=7, thickness=5, offset=20)
            else:
                px, py = self.previousHead
                cx, cy = currentHead
     
                self.points.append([cx, cy])
                distance = math.hypot(cx - px, cy - py)
                self.lengths.append(distance)
                self.currentLength += distance
                self.previousHead = cx, cy
     
                #長(zhǎng)度縮小
                if self.currentLength > self.allowedLength:
                    for i, length in enumerate(self.lengths):
                        self.currentLength -= length
                        self.lengths.pop(i)
                        self.points.pop(i)
                        if self.currentLength < self.allowedLength:
                            break
     
                #檢查貪吃蛇是否已經(jīng)觸碰到食物
                rx, ry = self.foodPoint
                if rx - self.wFood // 2 < cx < rx + self.wFood // 2 and \
                        ry - self.hFood // 2 < cy < ry + self.hFood // 2:
                    self.randomFoodLocation()
                    self.allowedLength += 50
                    self.score += 1
                    print(self.score)
     
                #使用線條繪制貪吃蛇
                if self.points:
                    for i, point in enumerate(self.points):
                        if i != 0:
                            cv2.line(imgMain, self.points[i - 1], self.points[i], (0, 0, 255), 20)
                    cv2.circle(imgMain, self.points[-1], 20, (0, 255, 0), cv2.FILLED)
     
                #顯示食物
                imgMain = cvzone.overlayPNG(imgMain, self.imgFood,
                                            (rx - self.wFood // 2, ry - self.hFood // 2))
     
                cvzone.putTextRect(imgMain, f'Score: {self.score}', [50, 80],
                                   scale=3, thickness=3, offset=10)
     
                #檢測(cè)是否碰撞
                pts = np.array(self.points[:-2], np.int32)
                pts = pts.reshape((-1, 1, 2))
                cv2.polylines(imgMain, [pts], False, (0, 255, 0), 3)
                minDist = cv2.pointPolygonTest(pts, (cx, cy), True)
     
                if -1 <= minDist <= 1:
                    print("Hit")
                    self.gameOver = True
                    self.points = []  #蛇身上所有的點(diǎn)
                    self.lengths = []  #不同點(diǎn)之間的距離
                    self.currentLength = 0  #當(dāng)前蛇的長(zhǎng)度
                    self.allowedLength = 50  #最大允許長(zhǎng)度
                    self.previousHead = 0, 0  #先前的蛇的頭部
                    self.randomFoodLocation()
     
            return imgMain
     
     
    game = SnakeGameClass("Donut.png")
     
    while True:
        success, img = cap.read()
        img = cv2.flip(img, 1) #鏡像翻轉(zhuǎn)
        hands, img = detector.findHands(img, flipType=False)
        #檢測(cè)到第一個(gè)手,并標(biāo)記手部位置
        if hands:
            lmList = hands[0]['lmList']
            pointIndex = lmList[8][0:2] #第八個(gè)坐標(biāo)點(diǎn)的 x, y值,其中 z 值不被包括在里面
            #cv2.circle(img, pointIndex, 20, (200, 0, 200), cv2.FILLED) #在關(guān)鍵點(diǎn)處繪制一個(gè)圓點(diǎn)并進(jìn)行填充(此處只是示范,后面會(huì)更改)
            img = game.update(img, pointIndex)
     
        cv2.imshow("Image", img)
        key = cv2.waitKey(1)
        #按下‘r'重新開始游戲
        if key == ord('r'):
            game.gameOver = False

    至于需要使用到的甜甜圈的圖案,可以網(wǎng)上找一個(gè)合適的大小的圖案進(jìn)行替代即可。

    讀到這里,這篇“Python如何利用手勢(shì)識(shí)別實(shí)現(xiàn)貪吃蛇游戲”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

    分享標(biāo)題:Python如何利用手勢(shì)識(shí)別實(shí)現(xiàn)貪吃蛇游戲
    文章路徑:http://jinyejixie.com/article48/joodep.html

    成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、面包屑導(dǎo)航App設(shè)計(jì)、網(wǎng)站改版、ChatGPT、建站公司

    廣告

    聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

    成都網(wǎng)站建設(shè)
    云和县| 友谊县| 区。| 加查县| 新丰县| 法库县| 大埔县| 娄底市| 丹棱县| 苍梧县| 大埔县| 三亚市| 石首市| 四子王旗| 闸北区| 五常市| 个旧市| 新田县| 横峰县| 靖州| 鄂州市| 蛟河市| 广水市| 榆社县| 河南省| 宾阳县| 克拉玛依市| 红河县| 广平县| 阿巴嘎旗| 威海市| 汝城县| 翁源县| 东兰县| 南雄市| 昂仁县| 新和县| 资讯 | 财经| 额尔古纳市| 巩留县|