[AI人工智能教程]LattePanda+Mind+摄像头玩AI贪吃蛇 精华

1567浏览
查看: 1567|回复: 7

[AI人工智能教程] LattePanda+Mind+摄像头玩AI贪吃蛇

[复制链接]
本帖最后由 云天 于 2022-4-11 15:49 编辑

MonApril-202204117402..png

【项目说明】

今天和大家分享一下如何使用LattePanda+Mind+ mediapipe+opencv 自制贪吃蛇小游戏。规则:食指指尖控制蛇头,指尖每接触到黄色方块,计数加一,蛇身变长,方块随机切换位置。如果指尖停止移动,或者移动过程中蛇头撞到蛇身,那么游戏结束。点击键盘上的R键重新开始游戏。


【项目准备】1、CVzone简介
OpenCV是一个开源计算机视觉库,可提供播放不同图像和视频流的权限,还有助于端到端项目,如对象检测、人脸检测、对象跟踪等。
MediaPipe是一个主要用于构建音频、视频或任何时间序列数据的框架。在 MediaPipe 框架的帮助下,我们可以为不同的媒体处理功能构建管道。
CVzone是一个计算机视觉包,可以让我们轻松运行像人脸检测、手部跟踪、姿势估计等,以及图像处理和其他 AI 功能。它的核心是使用 OpenCV 和 MediaPipe 库。
2、安装所需的模块。

  1. -- pip install OpenCV-python
  2. -- pip install cvzone
  3. -- pip install mediapipe
复制代码
在Mind+中使用“库管理”——“PIP”模式安装以上这三个库
MonApril-202204043986..png

MonApril-202204042325..png

MonApril-202204047525..png

3、首先,让我们检查一下LattePanda安装的网络摄像头是否工作正常。

  1. import cv2
  2. cap = cv2.VideoCapture(0)
  3. cap.set(3, 640)
  4. cap.set(4, 480)
  5. while True:
  6.   success, img = cap.read()
  7.   cv2.imshow("Image", img)
  8.   if cv2.waitKey(1) & 0xFF == ord('q'):
  9.     break
复制代码

4、调用Mediapipe,识别手部关键点
MonApril-202204112468..png
21个手部关键点信息如下,本节我们主要研究食指指尖'8'的坐标(x,y)信息。

  1. import cvzone
  2. import cv2
  3. import numpy as np
  4. from cvzone.HandTrackingModule import HandDetector
  5. cap = cv2.VideoCapture(0)   # 0代表自己电脑的摄像头
  6. cap.set(3, 1280)        # 宽
  7. cap.set(4, 720)         # 高
  8. detector = HandDetector(detectionCon=0.8, maxHands=1)
  9. # 处理每一帧图像
  10. while True:
  11.     success, img = cap.read()
  12.     # 翻转图像,使自身和摄像头中的自己呈镜像关系
  13.     img = cv2.flip(img, 1)      # 将手水平翻转
  14.     hands, img = detector.findHands(img, flipType=False)    # 左手是左手,右手是右手,映射正确
  15.     cv2.imshow("Image", img)
  16.     cv2.waitKey(1)
复制代码
5、观察手的信息
  1. import cvzone
  2. import cv2
  3. import numpy as np
  4. from cvzone.HandTrackingModule import HandDetector
  5. cap = cv2.VideoCapture(0)   # 0代表自己电脑的摄像头
  6. cap.set(3, 1280)        # 宽
  7. cap.set(4, 720)         # 高
  8. detector = HandDetector(detectionCon=0.8, maxHands=1)
  9. # 处理每一帧图像
  10. while True:
  11.     success, img = cap.read()
  12.     # 翻转图像,使自身和摄像头中的自己呈镜像关系
  13.     img = cv2.flip(img, 1)      # 将手水平翻转
  14.     hands, img = detector.findHands(img, flipType=False)    # 左手是左手,右手是右手,映射正确
  15.     print(hands)
  16.     cv2.imshow("Image", img)
  17.     cv2.waitKey(1)
复制代码
输出信息
  1. [{‘lmList’: [[1088, 633, 0], [1012, 655, -24], [940, 629, -32], [894, 596, -35], [875, 562, -36], [949, 504, -17], [891, 441, -16], [862, 419, -16], [838, 403, -16], [995, 480, -3], [943, 418, 8], [924, 426, 17], [920, 440, 22], [1044, 480, 8], [998, 455, 17], [987, 489, 21], [993, 513, 23], [1085, 492, 19], [1048, 477, 27], [1036, 505, 35], [1041, 528, 40]], ‘bbox’: (838, 403, 250, 252), ‘center’: (963, 529), ‘type’: ‘Left’}]
复制代码


【硬件组装】
MonApril-202204115079..png
MonApril-202204118830..png




程序测试】
运行Mind+
MonApril-202204118943..png
测试识别手部关键点
MonApril-202204119887..png

【完整程序】
  1. import cv2
  2. import cvzone
  3. from matplotlib.cbook import pts_to_midstep
  4. import numpy as np
  5. from cvzone.HandTrackingModule import HandDetector # 导入手部检测模块
  6. import math
  7. import random
  8.    
  9. # 构造一个贪吃蛇移动的类
  10. class SnakeGameClass:
  11.    
  12.      #(一)初始化
  13.      def __init__(self):
  14.    
  15.          self.score = 0 # 积分器
  16.          self.points = [] # 蛇的身体的节点坐标
  17.          self.lengths = [] # 蛇身各个节点之间的坐标
  18.          self.currentLength = 0 # 当前蛇身长度
  19.          self.allowedLength = 150 # 没吃东西时,蛇的总长度
  20.          self.previousHead = (0,0) # 前一个蛇头节点的坐标
  21.    
  22.          self.foodPoint = (0,0) # 食物的起始位置
  23.          self.randomFoodLocation() # 随机改变食物的位置
  24.    
  25.          self.gameover = False # 蛇头撞到蛇身,变成True,游戏结束
  26.    
  27.      #(二)食物随机出现的位置
  28.      def randomFoodLocation(self):
  29.          # x在100至1000之间,y在100至600之间,随机取一个整数
  30.          self.foodPoint = random.randint(100, 1000), random.randint(100, 600)
  31.    
  32.      #(三)更新增加蛇身长度
  33.      def update(self, imgMain, currentHead): # 输入图像,当前蛇头的坐标
  34.    
  35.          # 游戏结束,显示文本
  36.          if self.gameover:
  37.              cvzone.putTextRect(imgMain, 'GameOver', [400,300], 5, 3, colorR=(0,255,255), colorT=(0,0,255))
  38.              cvzone.putTextRect(imgMain, f'Score:{self.score}', [450,400], 5, 3, colorR=(255,255,0))
  39.              cvzone.putTextRect(imgMain, f"Press Key 'R' to Restart", [230,500], 4, 3, colorR=(0,255,0), colorT=(255,0,0))
  40.    
  41.          else:
  42.              px, py = self.previousHead # 获得前一个蛇头的x和y坐标
  43.              cx, cy = currentHead # 当前蛇头节点的x和y坐标
  44.             
  45.              # 添加当前蛇头的坐标到蛇身节点坐标列表中
  46.              self.points.append([cx,cy])
  47.    
  48.              # 计算两个节点之间的距离
  49.              distance = math.hypot(cx-px, cy-py) # 计算平方和开根
  50.              # 将节点之间的距离添加到蛇身节点距离列表中
  51.              self.lengths.append(distance)
  52.              # 增加当前蛇身长度
  53.              self.currentLength += distance
  54.    
  55.              # 更新蛇头坐标
  56.              self.previousHead = (cx,cy)
  57.    
  58.              #(四)减少蛇尾长度,即移动过程中蛇头到蛇尾的长度不大于150
  59.              if self.currentLength > self.allowedLength:
  60.    
  61.                  # 遍历所有的节点线段长度。新更新的蛇头索引在列表后面,蛇尾的索引在列表前面
  62.                  for i, length in enumerate(self.lengths):
  63.    
  64.                      # 从蛇尾到蛇头依次减线段长度,得到的长度是否满足要求
  65.                      self.currentLength -= length
  66.    
  67.                      # 从列表中删除蛇尾端的线段长度,以及蛇尾节点
  68.                      self.lengths.pop(i)
  69.                      self.points.pop(i)
  70.    
  71.                      # 如果当前蛇身长度小于规定长度,满足要求,退出循环
  72.                      if self.currentLength < self.allowedLength:
  73.                       break
  74.             
  75.              #(五)绘制得分板
  76.              cvzone.putTextRect(imgMain, f'Score:{self.score}', [50,80], 4, 3, colorR=(255,255,0))
  77.    
  78.              #(六)检查蛇是否吃了食物
  79.              rx, ry = self.foodPoint # 得到食物的中心点坐标位置
  80.             
  81.              # 绘制矩形作为蛇的食物
  82.              cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (255,255,0), cv2.FILLED)
  83.              cv2.rectangle(imgMain, (rx-20, ry-20), (rx+20, ry+20), (0,255,255), 5)
  84.              cv2.rectangle(imgMain, (rx-5, ry-5), (rx+5, ry+5), (0,0,255), cv2.FILLED)
  85.    
  86.              # 检查指尖(即蛇头cx,cy)是否在矩形内部
  87.              if rx-20 < cx < rx+20 and ry-20< cy < ry+20:
  88.    
  89.                  # 随机更换食物的位置
  90.                  self.randomFoodLocation()
  91.    
  92.                  # 增加蛇身的限制长度,每吃1个食物就能变长50
  93.                  self.allowedLength += 50
  94.    
  95.                  # 吃食物的计数加一
  96.                  self.score += 1
  97.    
  98.                  print('eat!', f'score:{self.score}')
  99.    
  100.              #(七)绘制蛇
  101.              # 当节点列表中有值了,才能绘制
  102.              if self.points:
  103.    
  104.                  # 遍历蛇身节点坐标
  105.                  for i, point in enumerate(self.points):
  106.                      # 绘制前后两个节点之间的连线
  107.                      if i != 0:
  108.                       cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,255,0), 20)
  109.                       cv2.line(imgMain, tuple(self.points[i-1]), tuple(self.points[i]), (0,0,255), 15)
  110.    
  111.                  # 在蛇头的位置画个圆
  112.                  cv2.circle(imgMain, tuple(self.points[-1]), 20, (255,255,0), cv2.FILLED)
  113.                  cv2.circle(imgMain, tuple(self.points[-1]), 18, (255,0,0), 3)
  114.                  cv2.circle(imgMain, tuple(self.points[-1]), 5, (0,0,0), cv2.FILLED)
  115.    
  116.              #(八)检查蛇头碰撞到自身
  117.              for point in self.points[:-2]: # 不算蛇头到自身的距离
  118.    
  119.                  # 计算蛇头和每个节点之间的距离
  120.                  dist = math.hypot(cx-point[0], cy-point[1])
  121.    
  122.                  # 如果距离小于1.8,那么就证明碰撞了
  123.                  if dist < 1.8:
  124.    
  125.                      # 游戏结束
  126.                      self.gameover = True
  127.    
  128.          # 返回更新后的图像
  129.          return imgMain
  130.    
  131.    
  132. #(1)获取摄像头
  133. cap = cv2.VideoCapture(0) # 0代表电脑自带的摄像头
  134. # 设置显示窗口的size
  135. cap.set(3, 1280) # 窗口宽1280
  136. cap.set(4, 720) # 窗口高720
  137.    
  138. #(2)模型配置
  139. detector = HandDetector(maxHands=1, # 最多检测1只手
  140.                      detectionCon=0.8) # 最小检测置信度0.8
  141.    
  142. # 接收创建贪吃蛇的类
  143. game = SnakeGameClass()
  144.    
  145. #(3)图像处理
  146. while True:
  147.    
  148.      # 每次读取一帧相机图像,返回是否读取成功success,读取的帧图像img
  149.      success, img = cap.read()
  150.    
  151.      # 图像翻转,使图像和自己呈镜像关系
  152.      img = cv2.flip(img, 1) # 0代表上下翻转,1代表左右翻转
  153.    
  154.      # 检测手部关键点。返回手部信息hands,绘制关键点后的图像img
  155.      hands, img = detector.findHands(img, flipType=False) # 由于上一行翻转过图像了,这里就不用翻转了
  156.    
  157.      #(4)关键点处理
  158.      if hands: # 如果检测到手了,那就处理关键点
  159.    
  160.          # 获得食指指尖坐标(x,y)
  161.          hand = hands[0] # 获取一只手的全部信息
  162.          lmList = hand['lmList'] # 获得这只手的21个关键点的坐标(x,y,z)
  163.          pointIndex = lmList[8][0:2] # 只获取食指指尖关键点的(x,y)坐标
  164.    
  165.          # 更新贪吃蛇的节点,给出蛇头节点坐标。返回更新后的图像
  166.          img = game.update(img, pointIndex)
  167.    
  168.      #(5)显示图像
  169.      cv2.imshow('img', img) # 输入图像显示窗口的名称及图像
  170.    
  171.      # 重新开始游戏
  172.      k = cv2.waitKey(1) # 每帧滞留1毫秒后消失
  173.      if k == ord('r'): # 键盘'r'键代表重新开始游戏
  174.          game.gameover = False
  175.          game.score = 0 # 积分器
  176.          game.points = [] # 蛇的身体的节点坐标
  177.          game.lengths = [] # 蛇身各个节点之间的坐标
  178.          game.currentLength = 0 # 当前蛇身长度
  179.          game.allowedLength = 150 # 没吃东西时,蛇的总长度
  180.          game.previousHead = (0,0) # 前一个蛇头节点的坐标
  181.          game.randomFoodLocation() # 随机改变食物的位置
  182.    
  183.      if k & 0xFF == 27: # 键盘ESC键退出程序
  184.          break
  185.    
  186. # 释放视频资源
  187. cap.release()
  188. cv2.destroyAllWindows()
复制代码


MonApril-202204116585..png

【演示视频】

MonApril-202204116122..png

云天  高级技匠
 楼主|

发表于 2022-4-11 15:49:10

回复

使用道具 举报

hnyzcj  版主

发表于 2022-4-11 15:53:49

回复

使用道具 举报

 初级技匠

发表于 2022-4-13 10:54:40

有点儿没懂。那台电脑是你用拿铁熊猫做的吗?
回复

使用道具 举报

rzegkly  版主

发表于 2022-4-17 12:14:19

漂亮,喜欢
回复

使用道具 举报

云天  高级技匠
 楼主|

发表于 2022-4-18 16:49:21

诩 发表于 2022-4-13 10:54
有点儿没懂。那台电脑是你用拿铁熊猫做的吗?

就是用拿铁熊猫做的
回复

使用道具 举报

小企鹅  高级技师

发表于 2022-4-23 17:13:17

厉害厉害
回复

使用道具 举报

派大星ym  高级技师

发表于 2022-8-2 08:53:12

。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2022 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail