社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

一小时学会用 Opencv 做贪吃蛇游戏(Python版)

小白学视觉 • 3 年前 • 285 次点击  

点击上方小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

作者 | 源代码•宸
来源丨CSDN博客

使用Mediapipe

水平镜像处理

import cvzoneimport cv2import numpy as npfrom cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己电脑的摄像头cap.set(3, 1280) # 宽cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=2)
# 处理每一帧图像while True: success, img = cap.read() # 翻转图像,使自身和摄像头中的自己呈镜像关系 img = cv2.flip(img, 1) # 将手水平翻转 hands, img = detector.findHands(img) cv2.imshow("Image", img) cv2.waitKey(1)

修改代码

import cvzoneimport cv2import numpy as npfrom cvzone.HandTrackingModule import HandDetectorcap = cv2.VideoCapture(0)   # 0代表自己电脑的摄像头cap.set(3, 1280)        # 宽cap.set(4, 720)         # 高detector = HandDetector(detectionCon=0.8, maxHands=1)# 处理每一帧图像while True:    success, img = cap.read()    # 翻转图像,使自身和摄像头中的自己呈镜像关系    img = cv2.flip(img, 1)      # 将手水平翻转    hands, img = detector.findHands(img, flipType=False)    # 左手是左手,右手是右手,映射正确    cv2.imshow("Image", img)    cv2.waitKey(1)
问题修复完毕

观察手的信息

import cvzoneimport cv2import numpy as npfrom cvzone.HandTrackingModule import HandDetectorcap = cv2.VideoCapture(0)   # 0代表自己电脑的摄像头cap.set(3, 1280)        # 宽cap.set(4, 720)         # 高detector = HandDetector(detectionCon=0.8, maxHands=1)# 处理每一帧图像while True:    success, img = cap.read()    # 翻转图像,使自身和摄像头中的自己呈镜像关系    img = cv2.flip(img, 1)      # 将手水平翻转    hands, img = detector.findHands(img, flipType=False)    # 左手是左手,右手是右手,映射正确    print(hands)    cv2.imshow("Image", img)    cv2.waitKey(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’}]
做个小蛇
import math
import cvzoneimport cv2import numpy as npfrom cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己电脑的摄像头cap.set(3, 1280) # 宽cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)

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 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
# Draw Snake 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, (200, 0, 200), cv2.FILLED) return imgMain
game = SnakeGameClass()
# 处理每一帧图像while True: # 不断迭代更新 success, img = cap.read() # 翻转图像,使自身和摄像头中的自己呈镜像关系 img = cv2.flip(img, 1) # 将手水平翻转 hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正确
if hands: lmList = hands[0]['lmList'] # hands是由N个字典组成的列表 pointIndex = lmList[8][0:2] # 只要食指指尖的x和y坐标 img = game.update(img, pointIndex)
cv2.imshow("Image", img)    cv2.waitKey(1)

添加甜甜圈

import mathimport random
import cvzoneimport cv2import numpy as npfrom cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己电脑的摄像头cap.set(3, 1280) # 宽cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)

class SnakeGameClass: def __init__(self, pathFood): # 构造方法 self.points = [] # 蛇身上所有的点 self.lengths = [] # 每个点之间的长度 self.currentLength = 0 # 蛇的总长 self.allowedLength = 150 # 蛇允许的总长度 self.previousHead = 0, 0 # 第二个头结点
self.imgFood = cv2.imread(pathFood, cv2.IMREAD_UNCHANGED) self.hFood, self.wFood, _ = self.imgFood.shape self.foodPoint = 0, 0 self.randomFoodLocation()
def randomFoodLocation(self): self.foodPoint = random.randint(100, 1000), random.randint(100, 600)

def update(self, imgMain, currentHead): # 实例方法
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
# Length Reduction 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

# Draw Snake 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, (200, 0, 200), cv2.FILLED)
# Draw Food rx, ry = self.foodPoint imgMain = cvzone.overlayPNG(imgMain, self.imgFood, (rx - self.wFood // 2, ry - self.hFood // 2))

return imgMain
game = SnakeGameClass("donut.png")
# 处理每一帧图像while True: # 不断迭代更新 success, img = cap.read() # 翻转图像,使自身和摄像头中的自己呈镜像关系 img = cv2.flip(img, 1) # 将手水平翻转 hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正确
if hands: lmList = hands[0]['lmList'] # hands是由N个字典组成的列表 pointIndex = lmList[8][0:2] # 只要食指指尖的x和y坐标 img = game.update(img, pointIndex)
cv2.imshow("Image", img)    cv2.waitKey(1)
donut.png

部分代码解释说明

imgMain = cvzone.overlayPNG(imgMain, self.imgFood,                                    (rx - self.wFood // 2, ry - self.hFood // 2))

为什么不是
imgMain = cvzone.overlayPNG(imgMain, self.imgFood, (rx , ry))
那是因为,随机生成一个点后,有坐标(x,y)

增加分数机制

import mathimport random
import cvzoneimport cv2import numpy as npfrom cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己电脑的摄像头cap.set(3, 1280) # 宽cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)

class SnakeGameClass: def __init__(self, pathFood): # 构造方法 self.points = [] # 蛇身上所有的点 self.lengths = [] # 每个点之间的长度 self.currentLength = 0 # 蛇的总长 self.allowedLength = 150 # 蛇允许的总长度 self.previousHead = 0, 0 # 第二个头结点
self.imgFood = cv2.imread(pathFood, cv2.IMREAD_UNCHANGED) self.hFood, self.wFood, _ = self.imgFood.shape self.foodPoint = 0, 0 self.randomFoodLocation()
self.score = 0
def randomFoodLocation(self): self.foodPoint = random.randint(100, 1000), random.randint(100, 600)

def update(self, imgMain, currentHead): # 实例方法
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
# Length Reduction 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
# Check if snake ate the food 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)

# Draw Snake 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, (200, 0, 200), cv2.FILLED)
# Draw Food
imgMain = cvzone.overlayPNG(imgMain, self.imgFood, (rx - self.wFood // 2, ry - self.hFood // 2))

return imgMain
game = SnakeGameClass("donut.png")
# 处理每一帧图像while True: # 不断迭代更新 success, img = cap.read() # 翻转图像,使自身和摄像头中的自己呈镜像关系 img = cv2.flip(img, 1) # 将手水平翻转 hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正确
if hands: lmList = hands[0]['lmList'] # hands是由N个字典组成的列表 pointIndex = lmList[8][0:2] # 只要食指指尖的x和y坐标 img = game.update(img, pointIndex)
cv2.imshow("Image", img)     cv2.waitKey(1)

完整代码

import mathimport random
import cvzoneimport cv2import numpy as npfrom cvzone.HandTrackingModule import HandDetector
cap = cv2.VideoCapture(0) # 0代表自己电脑的摄像头cap.set(3, 1280) # 宽cap.set(4, 720) # 高
detector = HandDetector(detectionCon=0.8, maxHands=1)

class SnakeGameClass: def __init__(self, pathFood): # 构造方法 self.points = [] # 蛇身上所有的点 self.lengths = [] # 每个点之间的长度 self.currentLength = 0 # 蛇的总长 self.allowedLength = 150 # 蛇允许的总长度 self.previousHead = 0, 0 # 第二个头结点
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): # 实例方法
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
# Length Reduction 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
# Check if snake ate the food 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)

# Draw Snake 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, (200, 0, 200), cv2.FILLED)
# Draw Food
imgMain = cvzone.overlayPNG(imgMain, self.imgFood, (rx - self.wFood // 2, ry - self.hFood // 2))
cvzone.putTextRect(imgMain, f'Your Score:{self.score}', [50, 80], scale=3, thickness=5, offset=10)
# Check for Collision pts = np.array(self.points[:-2], np.int32) pts = pts.reshape((-1, 1, 2)) # 重塑为一个行数未知但只有一列且每个元素有2个子元素的矩阵 cv2.polylines(imgMain, [pts], False, (0, 200, 0), 3) # 第三个参数是False,我们得到的是不闭合的线 minDist = cv2.pointPolygonTest(pts, (cx, cy), True) # 参数True表示输出该像素点到轮廓最近距离
if -1 <= minDist <= 1: print("Hit") self.gameOver = True self.points = [] # 蛇身上所有的点 self.lengths = [] # 每个点之间的长度 self.currentLength = 0 # 蛇的总长 self.allowedLength = 150 # 蛇允许的总长度 self.previousHead = 0, 0 # 第二个头结点 self.randomFoodLocation()

return imgMain
game = SnakeGameClass("donut.png")
# 处理每一帧图像while True: # 不断迭代更新 success, img = cap.read() # 翻转图像,使自身和摄像头中的自己呈镜像关系 img = cv2.flip(img, 1) # 将手水平翻转 hands, img = detector.findHands(img, flipType=False) # 左手是左手,右手是右手,映射正确
if hands: lmList = hands[0]['lmList'] # hands是由N个字典组成的列表 pointIndex = lmList[8][0:2] # 只要食指指尖的x和y坐标 img = game.update(img, pointIndex)
cv2.imshow("Image", img) key = cv2.waitKey(1) if key == ord('r'):        game.gameOver = False
下载1:OpenCV-Contrib扩展模块中文版教程
在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目52讲
小白学视觉公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲
小白学视觉公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

交流群


欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/130439
 
285 次点击