千家信息网

怎么用Python+OpenCV自制AI视觉版贪吃蛇游戏

发表于:2025-11-10 作者:千家信息网编辑
千家信息网最后更新 2025年11月10日,今天小编给大家分享一下怎么用Python+OpenCV自制AI视觉版贪吃蛇游戏的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文
千家信息网最后更新 2025年11月10日怎么用Python+OpenCV自制AI视觉版贪吃蛇游戏

今天小编给大家分享一下怎么用Python+OpenCV自制AI视觉版贪吃蛇游戏的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

介绍

规则:食指指尖控制蛇头,指尖每接触到黄色方块,计数加一,蛇身变长,方块随机切换位置。如果指尖停止移动,或者移动过程中蛇头撞到蛇身,那么游戏结束。点击键盘上的R键重新开始游戏。

游戏进行时:

游戏结束界面:

1. 安装工具包

pip install opencv_python==4.2.0.34  # 安装opencvpip install mediapipe  # 安装mediapipe# pip install mediapipe --user  #有user报错的话试试这个pip install cvzone  # 安装cvzone # 导入工具包import cv2import cvzoneimport numpy as npfrom cvzone.HandTrackingModule import HandDetector  # 导入手部检测模块import mathimport random

21个手部关键点信息如下,本节我们主要研究食指指尖'8'的坐标(x,y)信息。

2. 检测手部关键点

(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组成。x和y分别由图像的宽度和高度归一化为[0,1]。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: 返回绘制了关键点及连线后的图像

代码如下:

import cv2import cvzoneimport numpy as npfrom cvzone.HandTrackingModule import HandDetector  # 导入手部检测模块 #(1)获取摄像头cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头# 设置显示窗口的sizecap.set(3, 1280)  # 窗口宽1280cap.set(4, 720)   # 窗口高720 #(2)模型配置detector = HandDetector(maxHands=1,  # 最多检测1只手                        detectionCon=0.8)  # 最小检测置信度0.8 #(3)图像处理while True:     # 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img    success, img = cap.read()     # 图像翻转,使图像和自己呈镜像关系    img = cv2.flip(img, 1)  # 0代表上下翻转,1代表左右翻转     # 检测手部关键点。返回手部信息hands,绘制关键点后的图像img    hands, img = detector.findHands(img, flipType=False)  # 由于上一行翻转过图像了,这里就不用翻转了     # 查看关键点信息    print(hands)     #(4)关键点处理    if hands:  # 如果检测到手了,那就处理关键点         # 获得食指指尖坐标(x,y)        hand = hands[0]  # 获取一只手的全部信息        lmList = hand['lmList']  # 获得这只手的21个关键点的坐标(x,y,z)        pointIndex = lmList[8][0:2]  # 只获取食指指尖关键点的(x,y)坐标         # 以食指指尖为圆心画圈(圆心坐标是元组类型),半径为15,青色填充        cv2.circle(img, tuple(pointIndex), 15, (255,0,0), cv2.FILLED)     #(5)显示图像    cv2.imshow('img', img)  # 输入图像显示窗口的名称及图像     # 每帧滞留1毫秒后消失,并且按下ESC键退出    if cv2.waitKey(1) & 0xFF == 27:        break # 释放视频资源cap.release()cv2.destroyAllWindows()

效果图如下:

打印手部关键点信息如下:

[{'lmList': [[1152, 675, 0], [1085, 693, -37], [1030, 698, -68], [1003, 698, -97], [1003, 679, -122], [1001, 511, -48], [1041, 546, -81], [1093, 608, -102], [1134, 652, -110], [1075, 484, -46], [1119, 534, -84], [1171, 605, -101], [1217, 659, -103], [1141, 481, -45], [1177, 529, -83], [1219, 590, -84], [1253, 642, -73], [1195, 494, -47], [1221, 521, -73], [1245, 566, -65], [1267, 602, -49]], 'bbox': (1001, 481, 266, 217),'center': (1134, 589), 'type': 'Right'}]

3. 蛇身移动

构造一个处理蛇身移动的类,要求在没吃食物时,蛇身保持固定的长度跟随食指指尖移动。

举个例子,如果当前的蛇身节点列表 self.points 包含 [a, b, c, d] 这四个节点,a节点代表蛇尾,d节点代表蛇头。在下一帧,食指指尖移动到 e 点,将 e 节点追加到蛇身节点列表中,那么现在的列表包含 [a, b, c, d, e] 节点,其中 e 节点为新的蛇头。

此时判断当前蛇身总长度 self.currentLength(列表中所有节点之间的长度之和)是否大于蛇身固定长度 self.allowedLength,保证在移动过程中蛇身长度不变。

如果当前蛇身总长度 self.currentLength 大于固定长度 self.allowedLength,那么在节点列表中从尾到头依次删除节点,列表 [a, b, c, d, e] 中 a 表示蛇尾节点,先删除,判断列表 [b, c, d, e] 的节点之间的总长度是否满足要求。若仍大于固定长度,那么就再删除 b 节点,再判断。

如果当前蛇身总长度 self.currentLength 小于固定长度 self.allowedLength,那么就不做任何处理。

在上述代码中补充:

import cv2import cvzoneimport numpy as npfrom cvzone.HandTrackingModule import HandDetector  # 导入手部检测模块import math # 构造一个贪吃蛇移动的类class SnakeGameClass:     #(一)初始化    def __init__(self):         self.points = []  # 蛇的身体的节点坐标        self.lengths = []  # 蛇身各个节点之间的坐标        self.currentLength = 0  # 当前蛇身长度        self.allowedLength = 150  # 没吃东西时,蛇的总长度        self.previousHead = (0,0)  # 前一个蛇头节点的坐标     #(二)更新增加蛇身长度    def update(self, imgMain, currentHead): # 输入图像,当前蛇头的坐标         px, py = self.previousHead  # 获得前一个蛇头的x和y坐标        cx, cy = currentHead  # 当前蛇头节点的x和y坐标                # 添加当前蛇头的坐标到蛇身节点坐标列表中        self.points.append([cx,cy])         # 计算两个节点之间的距离        distance = math.hypot(cx-px, cy-py)  # 计算平方和开根        # 将节点之间的距离添加到蛇身节点距离列表中        self.lengths.append(distance)        # 增加当前蛇身长度        self.currentLength += distance         # 更新蛇头坐标        self.previousHead = (cx,cy)         #(三)减少蛇尾长度,即移动过程中蛇头到蛇尾的长度不大于150        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         #(四)绘制蛇        # 当节点列表中有值了,才能绘制        if self.points:             # 遍历蛇身节点坐标            for i, point in enumerate(self.points):                  # 绘制前后两个节点之间的连线                if i != 0:                    cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,255,0), 20)             # 在蛇头的位置画个圆            cv2.circle(imgMain, tuple(self.points[-1]), 20, (255,0,0), cv2.FILLED)         # 返回更新后的图像        return imgMain  #(1)获取摄像头cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头# 设置显示窗口的sizecap.set(3, 1280)  # 窗口宽1280cap.set(4, 720)   # 窗口高720 #(2)模型配置detector = HandDetector(maxHands=1,  # 最多检测1只手                        detectionCon=0.8)  # 最小检测置信度0.8 # 接收创建贪吃蛇的类game = SnakeGameClass() #(3)图像处理while True:     # 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img    success, img = cap.read()     # 图像翻转,使图像和自己呈镜像关系    img = cv2.flip(img, 1)  # 0代表上下翻转,1代表左右翻转     # 检测手部关键点。返回手部信息hands,绘制关键点后的图像img    hands, img = detector.findHands(img, flipType=False)  # 由于上一行翻转过图像了,这里就不用翻转了     # 查看关键点信息    print(hands)     #(4)关键点处理    if hands:  # 如果检测到手了,那就处理关键点         # 获得食指指尖坐标(x,y)        hand = hands[0]  # 获取一只手的全部信息        lmList = hand['lmList']  # 获得这只手的21个关键点的坐标(x,y,z)        pointIndex = lmList[8][0:2]  # 只获取食指指尖关键点的(x,y)坐标         # 更新贪吃蛇的节点,给出蛇头节点坐标。返回更新后的图像        img = game.update(img, pointIndex)     #(5)显示图像    cv2.imshow('img', img)  # 输入图像显示窗口的名称及图像     # 每帧滞留1毫秒后消失,并且按下ESC键退出    if cv2.waitKey(1) & 0xFF == 27:        break # 释放视频资源cap.release()cv2.destroyAllWindows()

效果图如下,蛇身保持默认固定长度随着指尖而移动。

4. 蛇进食增加身体长度

先看下面代码 SnakeGameClass 类中的第(五)步。给食物(即绘制的矩形)随机给出一个中心点坐标,自定义的类方法 randomFoodLocation(),执行该方法则食物的中心点坐标的x在[100,1000]中随机取一个数,y在[100,600]中随机取一个数。

下面代码定义的类中的第(七)步。判断食指指尖(即蛇头节点坐标)是否在矩形内部,如果在内部,那么蛇身移动过程中的固定长度 self.allowedLength 增加50个像素值。得分 self.score 加一。并在下一帧随机改变食物的位置。

在上述代码中补充:

import cv2import cvzoneimport numpy as npfrom cvzone.HandTrackingModule import HandDetector  # 导入手部检测模块import mathimport random # 构造一个贪吃蛇移动的类class SnakeGameClass:     #(一)初始化    def __init__(self):         self.score = 0  # 积分器        self.points = []  # 蛇的身体的节点坐标        self.lengths = []  # 蛇身各个节点之间的坐标        self.currentLength = 0  # 当前蛇身长度        self.allowedLength = 150  # 没吃东西时,蛇的总长度        self.previousHead = (0,0)  # 前一个蛇头节点的坐标         self.foodPoint = (0,0)  # 食物的起始位置        self.randomFoodLocation()  # 随机改变食物的位置     #(五)食物随机出现的位置    def randomFoodLocation(self):        # x在100至1000之间,y在100至600之间,随机取一个整数        self.foodPoint = random.randint(100, 1000),  random.randint(100, 600)     #(二)更新增加蛇身长度    def update(self, imgMain, currentHead): # 输入图像,当前蛇头的坐标         px, py = self.previousHead  # 获得前一个蛇头的x和y坐标        cx, cy = currentHead  # 当前蛇头节点的x和y坐标                # 添加当前蛇头的坐标到蛇身节点坐标列表中        self.points.append([cx,cy])         # 计算两个节点之间的距离        distance = math.hypot(cx-px, cy-py)  # 计算平方和开根        # 将节点之间的距离添加到蛇身节点距离列表中        self.lengths.append(distance)        # 增加当前蛇身长度        self.currentLength += distance         # 更新蛇头坐标        self.previousHead = (cx,cy)         #(三)减少蛇尾长度,即移动过程中蛇头到蛇尾的长度不大于150        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                #(七)检查蛇是否吃了食物        rx, ry = self.foodPoint  # 得到食物的中心点坐标位置                # 绘制矩形作为蛇的食物        cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (255,255,0), cv2.FILLED)        cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (0,255,255), 5)                cv2.rectangle(imgMain, (rx-5, ry-5), (rx+5, ry+5), (0,0,255), cv2.FILLED)           # 检查指尖(即蛇头cx,cy)是否在矩形内部        if rx-20 < cx < rx+20 and ry-20< cy < ry+20:             # 随机更换食物的位置            self.randomFoodLocation()             # 增加蛇身的限制长度,每吃1个食物就能变长50            self.allowedLength += 50             # 吃食物的计数加一            self.score += 1             print('eat!', f'score:{self.score}')         #(四)绘制蛇        # 当节点列表中有值了,才能绘制        if self.points:             # 遍历蛇身节点坐标            for i, point in enumerate(self.points):                  # 绘制前后两个节点之间的连线                if i != 0:                    cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,255,0), 20)                    cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,0,255), 15)             # 在蛇头的位置画个圆            cv2.circle(imgMain, tuple(self.points[-1]), 20, (255,255,0), cv2.FILLED)            cv2.circle(imgMain, tuple(self.points[-1]), 18, (255,0,0), 3)                        cv2.circle(imgMain, tuple(self.points[-1]), 5, (0,0,0), cv2.FILLED)         # 返回更新后的图像        return imgMain  #(1)获取摄像头cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头# 设置显示窗口的sizecap.set(3, 1280)  # 窗口宽1280cap.set(4, 720)   # 窗口高720 #(2)模型配置detector = HandDetector(maxHands=1,  # 最多检测1只手                        detectionCon=0.8)  # 最小检测置信度0.8 # 接收创建贪吃蛇的类game = SnakeGameClass() #(3)图像处理while True:     # 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img    success, img = cap.read()     # 图像翻转,使图像和自己呈镜像关系    img = cv2.flip(img, 1)  # 0代表上下翻转,1代表左右翻转     # 检测手部关键点。返回手部信息hands,绘制关键点后的图像img    hands, img = detector.findHands(img, flipType=False)  # 由于上一行翻转过图像了,这里就不用翻转了     #(4)关键点处理    if hands:  # 如果检测到手了,那就处理关键点         # 获得食指指尖坐标(x,y)        hand = hands[0]  # 获取一只手的全部信息        lmList = hand['lmList']  # 获得这只手的21个关键点的坐标(x,y,z)        pointIndex = lmList[8][0:2]  # 只获取食指指尖关键点的(x,y)坐标         # 更新贪吃蛇的节点,给出蛇头节点坐标。返回更新后的图像        img = game.update(img, pointIndex)     #(5)显示图像    cv2.imshow('img', img)  # 输入图像显示窗口的名称及图像     # 每帧滞留1毫秒后消失,并且按下ESC键退出    if cv2.waitKey(1) & 0xFF == 27:        break # 释放视频资源cap.release()cv2.destroyAllWindows()

效果图如下:

5. 自身碰撞及界面的处理

先看到自定义类 SnakeGameClass 中的第(八)步,蛇身节点列表 self.points 中包含从蛇头到蛇尾的所有节点。如 [a, b, c, d, e] 节点,a 节点代表蛇尾,e 节点代表蛇头。这里我就粗糙地判断一下是否碰撞,如果大家有更好的判断方法可以改动这第(八)步。计算蛇头 e 节点到所有节点之间的距离,如果小于某个值就代表碰撞了,游戏结束 self.gameover = True

再看到自定义类中的第(三)步。如果游戏结束 self.gameover = True,那就在下一帧中绘制结算界面,不再执行蛇身移动程序。

再看到主程序中的第(5)步。其中 k == ord('r'),按下键盘上的 r 键来重新游戏。将所有蛇身变量初始化,并将 self.gameover = False,退出结算界面,使得下一帧能执行蛇身移动操作。

在上述代码中补充:

import cv2import cvzonefrom matplotlib.cbook import pts_to_midstepimport numpy as npfrom cvzone.HandTrackingModule import HandDetector  # 导入手部检测模块import mathimport random # 构造一个贪吃蛇移动的类class SnakeGameClass:     #(一)初始化    def __init__(self):         self.score = 0  # 积分器        self.points = []  # 蛇的身体的节点坐标        self.lengths = []  # 蛇身各个节点之间的坐标        self.currentLength = 0  # 当前蛇身长度        self.allowedLength = 150  # 没吃东西时,蛇的总长度        self.previousHead = (0,0)  # 前一个蛇头节点的坐标         self.foodPoint = (0,0)  # 食物的起始位置        self.randomFoodLocation()  # 随机改变食物的位置         self.gameover = False  # 蛇头撞到蛇身,变成True,游戏结束     #(二)食物随机出现的位置    def randomFoodLocation(self):        # x在100至1000之间,y在100至600之间,随机取一个整数        self.foodPoint = random.randint(100, 1000),  random.randint(100, 600)     #(三)更新增加蛇身长度    def update(self, imgMain, currentHead): # 输入图像,当前蛇头的坐标         # 游戏结束,显示文本        if self.gameover:            cvzone.putTextRect(imgMain, 'GameOver', [400,300], 5, 3, colorR=(0,255,255), colorT=(0,0,255))            cvzone.putTextRect(imgMain, f'Score:{self.score}', [450,400], 5, 3, colorR=(255,255,0))            cvzone.putTextRect(imgMain, f"Press Key 'R' to Restart", [230,500], 4, 3, colorR=(0,255,0), colorT=(255,0,0))         else:            px, py = self.previousHead  # 获得前一个蛇头的x和y坐标            cx, cy = currentHead  # 当前蛇头节点的x和y坐标                        # 添加当前蛇头的坐标到蛇身节点坐标列表中            self.points.append([cx,cy])             # 计算两个节点之间的距离            distance = math.hypot(cx-px, cy-py)  # 计算平方和开根            # 将节点之间的距离添加到蛇身节点距离列表中            self.lengths.append(distance)            # 增加当前蛇身长度            self.currentLength += distance             # 更新蛇头坐标            self.previousHead = (cx,cy)             #(四)减少蛇尾长度,即移动过程中蛇头到蛇尾的长度不大于150            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                        #(五)绘制得分板            cvzone.putTextRect(imgMain, f'Score:{self.score}', [50,80], 4, 3, colorR=(255,255,0))             #(六)检查蛇是否吃了食物            rx, ry = self.foodPoint  # 得到食物的中心点坐标位置                        # 绘制矩形作为蛇的食物            cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (255,255,0), cv2.FILLED)            cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (0,255,255), 5)                    cv2.rectangle(imgMain, (rx-5, ry-5), (rx+5, ry+5), (0,0,255), cv2.FILLED)               # 检查指尖(即蛇头cx,cy)是否在矩形内部            if rx-20 < cx < rx+20 and ry-20< cy < ry+20:                 # 随机更换食物的位置                self.randomFoodLocation()                 # 增加蛇身的限制长度,每吃1个食物就能变长50                self.allowedLength += 50                 # 吃食物的计数加一                self.score += 1                 print('eat!', f'score:{self.score}')             #(七)绘制蛇            # 当节点列表中有值了,才能绘制            if self.points:                 # 遍历蛇身节点坐标                for i, point in enumerate(self.points):                      # 绘制前后两个节点之间的连线                    if i != 0:                        cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,255,0), 20)                        cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,0,255), 15)                 # 在蛇头的位置画个圆                cv2.circle(imgMain, tuple(self.points[-1]), 20, (255,255,0), cv2.FILLED)                cv2.circle(imgMain, tuple(self.points[-1]), 18, (255,0,0), 3)                            cv2.circle(imgMain, tuple(self.points[-1]), 5, (0,0,0), cv2.FILLED)             #(八)检查蛇头碰撞到自身                    for point in self.points[:-2]:  # 不算蛇头到自身的距离                 # 计算蛇头和每个节点之间的距离                dist = math.hypot(cx-point[0], cy-point[1])                 # 如果距离小于1.8,那么就证明碰撞了                if dist < 1.8:                     # 游戏结束                    self.gameover = True         # 返回更新后的图像        return imgMain  #(1)获取摄像头cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头# 设置显示窗口的sizecap.set(3, 1280)  # 窗口宽1280cap.set(4, 720)   # 窗口高720 #(2)模型配置detector = HandDetector(maxHands=1,  # 最多检测1只手                        detectionCon=0.8)  # 最小检测置信度0.8 # 接收创建贪吃蛇的类game = SnakeGameClass() #(3)图像处理while True:     # 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img    success, img = cap.read()     # 图像翻转,使图像和自己呈镜像关系    img = cv2.flip(img, 1)  # 0代表上下翻转,1代表左右翻转     # 检测手部关键点。返回手部信息hands,绘制关键点后的图像img    hands, img = detector.findHands(img, flipType=False)  # 由于上一行翻转过图像了,这里就不用翻转了     #(4)关键点处理    if hands:  # 如果检测到手了,那就处理关键点         # 获得食指指尖坐标(x,y)        hand = hands[0]  # 获取一只手的全部信息        lmList = hand['lmList']  # 获得这只手的21个关键点的坐标(x,y,z)        pointIndex = lmList[8][0:2]  # 只获取食指指尖关键点的(x,y)坐标         # 更新贪吃蛇的节点,给出蛇头节点坐标。返回更新后的图像        img = game.update(img, pointIndex)     #(5)显示图像    cv2.imshow('img', img)  # 输入图像显示窗口的名称及图像     # 重新开始游戏    k = cv2.waitKey(1)  # 每帧滞留1毫秒后消失    if k == ord('r'):  # 键盘'r'键代表重新开始游戏        game.gameover = False        game.score = 0  # 积分器        game.points = []  # 蛇的身体的节点坐标        game.lengths = []  # 蛇身各个节点之间的坐标        game.currentLength = 0  # 当前蛇身长度        game.allowedLength = 150  # 没吃东西时,蛇的总长度        game.previousHead = (0,0)  # 前一个蛇头节点的坐标                        game.randomFoodLocation()  # 随机改变食物的位置        if k & 0xFF == 27:  # 键盘ESC键退出程序        break # 释放视频资源cap.release()cv2.destroyAllWindows()

效果图如下,在移动过程中,蛇头每碰到一个食物,蛇身就会变长,如果 停止移动 或 蛇头节点距离蛇身节点过近 就会结束游戏。

以上就是"怎么用Python+OpenCV自制AI视觉版贪吃蛇游戏"这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注行业资讯频道。

节点 坐标 图像 长度 蛇头 检测 关键 关键点 手部 之间 蛇尾 食物 指尖 更新 移动 代表 位置 处理 信息 食指 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 有关校园网络安全的黑板报 数据库sys用户忘记密码 数字书法软件开发 桦甸市天气预报软件开发 玩cf为啥一直服务器断开连接 招软件开发的有哪些专科学校 原神 阿里云服务器费用 青岛戴尔服务器代理联系方式 mysql数据库误删 如何查找一个服务器的域名 财务分析数据库 新疆大学网络安全协会 相城区信息化网络技术怎么样 物联网终端的软件开发 云浮软件开发公司 广播电视网络技术就业 获取嫌疑人服务器 软件开发实施过程 医院网络安全工作台账目录 挖财网络技术有限公司工资 四川计算机网络技术职业学校 轻应用服务器一运行就挂 青椒第二课堂网络安全教育平台 网络安全渗透工程师(网警) 翻译英语单词软件开发 网络安全模式连不了wifi 美团优选老说服务器错误403 外包软件开发工作要求 软件开发交流微信群 晋中师范高等专科学校网络技术
0