介绍

各位同学好,今天和大家分享一下如何使用 mediapipe+opencv 自制贪吃蛇小游戏。先放张图看效果。

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

游戏进行时:

游戏结束界面:

1. 安装工具包

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: 返回绘制了关键点及连线后的图像

代码如下:

效果图如下:

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

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,那么就不做任何处理。

在上述代码中补充:

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

4. 蛇进食增加身体长度

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

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

在上述代码中补充:

效果图如下:

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,退出结算界面,使得下一帧能执行蛇身移动操作。

在上述代码中补充:

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

以上就是python+opencv自制ai视觉版贪吃蛇游戏的详细内容,更多关于python opencv贪吃蛇的资料请关注www.887551.com其它相关文章!