★★★ 本文源自AlStudio社区精品项目,【点击此处】查看更多精品内容 >>>

【去后厂村开游戏厅吧】基于pp-tinypose的体感飙车避障游戏

本项目基于pp-tinypose和Fastdeploy识别手腕位置,模拟方向盘转动,控制小车在道路上移动,躲避障碍车辆。

准备好项目所需环境后,fork本项目,将demo.zip下载到本地,运行其中的main.py即可

游戏介绍和效果展示

左侧是游戏画面,右侧是人物和检测结果。程序检测身上的关键点位置(手腕),并计算偏移角度作为小车移动的方向和速度,并躲避障碍物。

游戏开始的方式采用了非常帅气的双手交叉变身姿势 = w <,撞车会显示这次的游戏时间作为得分,双手再次交叉即可重新开始游戏~

环境准备

运行本项目需要准备:PC(带有CPU即可),USB摄像头(笔记本自带的摄像头也可以)。

友情链接

【去后厂村开游戏厅吧】基于pp-tinypose的体感贪吃蛇游戏

部署流程

PP-TinyPose 和 FastDeploy

介绍参考【去后厂村开游戏厅吧】基于pp-tinypose的体感贪吃蛇游戏

基于PyQt5的Paddle飙车小游戏

以下代码需要在本地运行,不能再Aistudio上运行的~

整体来说比较简单,这个部分比起与深度学习有关的项目介绍更像是游戏构造讲解,有兴趣的可以康康~

PyQt5

基于PyQt5的一般创建和运行流程如下,简单来说,就是在init里写页面布局,定义行为关系(例如点击按钮会调用哪个函数等等)。

import sys
import cv2
import numpy as np
import paddle
import math
import time
import collections
import os
import sys
from PyQt5.QtWidgets import QWidget, QDesktopWidget, QApplication, QPushButton, QFileDialog, QLabel, QTextEdit, \QGridLayout, QFrame, QColorDialog
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QColor, QImage, QPixmapclass Example(QWidget):def __init__(self):super().__init__()# 初始化相关变量、定义界面布局、将相关按钮关联到事件(函数)上def event1(self):# 点击第一个按钮所执行的事件(函数) def event1(self):# 点击第二个按钮所执行的事件(函数) if __name__ == '__main__':app = QApplication(sys.argv)ex = Example()sys.exit(app.exec_())

初始化

定义支撑游戏运行的基础信息

    def __init__(self):super().__init__()# 准备一张底图,后续的所有内容都是在这张图上绘制的。# 游戏界面卡死在500*500的大小# 虽然游戏界面卡死在500的大小,但是根据演示,我们需要在图片上贴上车辆的贴图,方便起见,扩大一下图片,这样保证所有的车辆图片都能贴在图片上,之后再进行裁剪self.map = np.ones([700, 500, 3]).astype('uint8') * 0# 绘制五车道,让画面更为真实# 让左右两侧都是绿化带self.map[:, 0:100, :] = (0, 255, 0)self.map[:, 400:-1, :] = (0, 255, 0)# 等间距画五条白线作为车道for i in [100, 160, 220, 280, 340, 400]:self.map[:, i-5:i+5, :] = (255, 255, 255)# 检测的关键点,这里本质上不用赋值成数组,但是因为这个程序我是从贪吃蛇那边复制了部分代码的,所以延续了数组的形式self.up_key_points = [9,9]# [0,0]self.down_key_points = [10,10]#[5,6]# 为了方便起见,我建立了一个叫做car的类,负责管理车辆的位置更新self.car = car() # 从CarObject 导入 Car# 一些游戏信息,比如根据关键点可以计算方向盘的角度self.direction = 0 # 判断角度self.game_status = 0 # 游戏状态 0 等待开始 1 进行# 初始化一些内容self.initModel() # 初始化模型self.initCamera() # 初始化摄像头self.initClock() # 初始化时钟self.initUI() # 初始化界面

模型初始化

通过fastdeploy调用检测模型只需要读取模型所在路径即可,将读取到的模型保存在model变量中,后续通过predict运行

    def initModel(self):self.model = fastdeploy.vision.keypointdetection.PPTinyPose('PP_TinyPose_128x96_infer/model.pdmodel','PP_TinyPose_128x96_infer/model.pdiparams','PP_TinyPose_128x96_infer/infer_cfg.yml')

初始化界面、时钟、视频

  • 界面:本游戏界面非常简单,仅由两个框体占据,所以通过QLabel创建两个框框即可
  • 视频:插入摄像头后必须把摄像头唤醒才能在后续推理的时候读取图像信息
  • 时钟:视频的本质就是图像,但是我们不可能彻底通过视频的方式处理事情。因此,需要通过QTimer()建立时钟,每隔一段时间唤醒一个自定义函数,这个函数就是我们进行推理,也就游戏控制的主函数了。
    def initUI(self):grid = QGridLayout()self.setLayout(grid)self.Game_Box = QLabel()  # 定义显示视频的Labelself.Game_Box.setFixedSize(500, 500)grid.addWidget(self.Game_Box, 0, 0, 20, 20)self.Game_Box.setMouseTracking(True)self.Pred_Box = QLabel()  # 定义显示视频的Labelself.Pred_Box.setFixedSize(500, 500)grid.addWidget(self.Pred_Box, 0, 20, 20, 20)self.setWindowTitle('Paddle Cars')self.show()def initCamera(self):# 开启视频通道self.camera_id = 0 # 为0时表示视频流来自摄像头self.camera = cv2.VideoCapture()  # 视频流self.camera.open(self.camera_id)def initClock(self):# 通过定时器读取数据self.flush_clock = QTimer()  # 定义定时器,用于控制显示视频的帧率self.flush_clock.start(30)   # 定时器开始计时30ms,结果是每过30ms从摄像头中取一帧显示self.flush_clock.timeout.connect(self.updata_frame)  # 若定时器结束,show_frame()

游戏推理和控制

上面已经通过时钟每隔一段时间调用一次self.updata_frame,下面来康康这个游戏主函数入口吧

    def updata_frame(self):# 读取图片,进行模型推理,更新self.directionself.inferModel()# 如果当前处于游戏状态,调用car更新车辆的位置信息if self.game_status == 1:self.car.update(self.direction)# 更新画面current_map = copy.deepcopy(self.map) # 复制底图current_map = self.car.draw(current_map)current_map = current_map[100:600,:,:] # 裁剪底图# 更新画面文字,当没有进入游戏状态,画面需要显示提示文字self.addText(current_map)# 展示图片showPic = QImage(current_map, current_map.shape[1], current_map.shape[0], QImage.Format_BGR888)self.Game_Box.setPixmap(QPixmap.fromImage(showPic))# 更新框体展示状态,如果当前在游戏状态,需要不停查看car的is_collision看看是否发生撞车if self.game_status == 1:if self.car.is_collision == 1:self.game_status = 2 # 游戏结束的评分页面

模型推理

    def inferModel(self):# read pic from camera_, img = self.camera.read()  # 从视频流中读取img = cv2.flip(img, 1) # 摄像头画面反转img2 = cv2.resize(img, (500, 500))  # 把读到的帧的大小重新设置为 640x480showPic = QImage(img2, img2.shape[1], img2.shape[0], QImage.Format_BGR888)self.Pred_Box.setPixmap(QPixmap.fromImage(showPic))try: # 推理会有失败的情况的,所以通过try可以规避这些问题导致程序崩溃result = self.model.predict(img) # 推理# 读取两个识别的关键点坐标top_y = (result.keypoints[self.up_key_points[0]][1] + result.keypoints[self.up_key_points[1]][1]) / 2top_x = (result.keypoints[self.up_key_points[0]][0] + result.keypoints[self.up_key_points[1]][0]) / 2bottom_y = (result.keypoints[self.down_key_points[0]][1] + result.keypoints[self.down_key_points[1]][1]) / 2bottom_x = (result.keypoints[self.down_key_points[0]][0] + result.keypoints[self.down_key_points[1]][0]) / 2# 如果当前不在游戏状态,需要判断游戏是否启动;否则计算偏转角度if self.game_status == 0 or self.game_status == 2:if abs(top_x-bottom_x) + abs(top_y-bottom_y) < 50:# 游戏启动,更新画面状态self.game_status = 1self.car.__init__()elif self.game_status == 1:self.direction = math.acos((top_y - bottom_y) / ((top_x - bottom_x) ** 2 + (top_y - bottom_y) ** 2) ** (1 / 2)) - math.pi/2# 在右侧显示摄像头画面img[int(top_y)-10:int(top_y)+10,int(top_x)-10:int(top_x)+10] = [0, 0, 255]img[int(bottom_y) - 10:int(bottom_y) + 10, int(bottom_x) - 10:int(bottom_x) + 10] = [0, 0, 255]showPic = QImage(img, img.shape[1], img.shape[0], QImage.Format_BGR888)self.Pred_Box.setPixmap(QPixmap.fromImage(showPic))except:print('infer error')

其他函数

可以看到除了关键的模型推理,还有car的定义,以及addText这样的辅助函数,具体如下~

  • addText
    def addText(self,img):if self.game_status == 0:img[75:350,50:450] = (134, 185, 222)cv2.putText(img, 'Paddle Cars', (60, 150), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 0), 5)cv2.putText(img, 'Hold the virtual steering wheel with both hands', (60, 180), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)cv2.putText(img, 'in the picture to control the car. The game',(60, 210), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)cv2.putText(img, 'ends when the car crashes. Try to stick to it',(60, 240), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)cv2.putText(img, 'for a longer time!',(60, 270), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)cv2.putText(img, 'Move your wrist so that two red dots cross to', (60, 310), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)cv2.putText(img, 'start!', (60, 340), cv2.FONT_HERSHEY_SIMPLEX, 0.5,(0, 0, 0), 1)elif self.game_status == 2:img[75:350,50:450] = (134, 185, 222)cv2.putText(img, 'Paddle Cars', (60, 150), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 0), 5)cv2.putText(img, 'YOUR SCORE', (180, 200), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)cv2.putText(img, self.car.show_time, (210, 240), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 255), 2)cv2.putText(img, 'Move your wrist so that two red dots cross to', (60, 310), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1)cv2.putText(img, 'start!', (60, 340), cv2.FONT_HERSHEY_SIMPLEX, 0.5,(0, 0, 0), 1)
  • car
import random
import cv2
import timeclass car(object):def __init__(self):# init game objectself.bias = 100 # 真实绘制地图大于实际展示部分,需要适当便宜绘制位点self.x = 250self.car = cv2.resize(cv2.imread('./Source/BlueCar.png'),(50, 100))self.enemy = cv2.resize(cv2.imread('./Source/RedCar.png'),(50, 100))self.barrier_list = []self.is_collision = 0 # 撞车标识 0 正常 1 撞车# 得分计数器self.time = time.time()self.now_time = time.time()self.show_time = "0:0:0"# 更新车道线self.COUNT = -50self.COUNT2 = 250def update(self, angle = 0): # angle 检测到的方向盘角度# 更新x信息self.x -= int(10*angle)# 更新障碍物if len(self.barrier_list) == 0 or random.random()<0.02:# x,y,speedself.barrier_list.append([int(random.random() * 200 + 150), -50, int(random.random() * 10 + 5)])# 更新位置for i in range(len(self.barrier_list)):self.barrier_list[i][1] += self.barrier_list[i][2]# 更新game_over status# TODO: 之后应该通过更灵活的方式实现for i in range(len(self.barrier_list)):if abs(self.barrier_list[i][1] - 450) < (self.car.shape[0] + self.enemy.shape[0]) * 0.9 / 2:if abs(self.barrier_list[i][0] - self.x) < (self.car.shape[1] + self.enemy.shape[1]) * 0.9 / 2:self.is_collision = 1# 删除无效数据self.barrier_list = [barrier for barrier in self.barrier_list if barrier[1]<549]if self.x < 100: self.x = 100if self.x > 400: self.x = 400# 车道线位置更新self.COUNT += 25self.COUNT2 += 25if self.COUNT >= 550: self.COUNT = -50if self.COUNT2 >= 550: self.COUNT2 = -50# 时间更新self.now_time = time.time()# 绘制def draw(self, img): # angle 检测到的方向盘角度# 绘制车道线,给人灵动的感觉for i in [160, 220, 280, 340]:img[self.COUNT-20+self.bias:self.COUNT+20+self.bias, i-5:i+5, :] = (0, 0, 0)img[self.COUNT2 - 20 + self.bias:self.COUNT2 + 20 + self.bias, i - 5:i + 5, :] = (0, 0, 0)# 绘制自己draw_car_in_pos(img,self.car,self.x, 450 + self.bias)# 绘制障碍车for barrier in self.barrier_list:draw_car_in_pos(img, self.enemy, barrier[0], barrier[1]+self.bias)# draw time# self.now_time在update更新tmp_time = self.now_time - self.timehour = int(tmp_time/3600)minute = int((tmp_time - hour*3600)/60)second = int(tmp_time - hour*3600 - minute*60)self.show_time = "{}:{}:{}".format(hour,minute,second)cv2.putText(img, self.show_time, (5, 50+self.bias), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (128, 128, 128), 2)return imgdef draw_car_in_pos(img,car_img,x,y,mask_id = 0):# img 画布# car_img 待贴合图片# x,y 绘制中心点h, w, _ = car_img.shapex1 = int(x-w/2)x2 = x1+wy1 = int(y-h/2)y2 = y1+htmp = img[y1:y2,x1:x2]tmp[car_img!=[0,0,0]]=car_img[car_img!=[0,0,0]]img[y1:y2,x1:x2] = tmp

结语

最后提醒大家一下,fork本项目,下载里面demo.zip到本地,并且保证本地python环境里安装了Fastdeploy、cv2、pyqt5就可以运行main.py快乐玩耍啦~

当然你赋值粘贴上面的代码也是可以啦~

最后的最后!

欢迎大家一起入股后厂村游戏厅呀!争取有一天将游戏厅开到Wave Summit里!

请点击此处查看本环境基本用法.

Please click here for more detailed instructions.

【去后厂村开游戏厅吧】基于pp-tinypose的体感飙车避障游戏相关推荐

  1. 去后厂村开游戏厅吧!基于PP-TinyPose的简易体感游戏开发框架

    ‍ 项目简介 近年来,随着虚拟现实技术和计算机图形学技术的迅猛发展,越来越多的体感游戏在市场上出现并受到欢迎.要让体感游戏具备良好的表现,就需要使用大量的传感器,甚至需要使用高性能的计算机和图形处理器 ...

  2. 【去后厂村开游戏厅吧】基于pp-tinypose的体感贪吃蛇游戏

    [去后厂村开游戏厅吧]基于pp-tinypose的体感贪吃蛇游戏 你是否也被腰痛所困扰!你是否也是久坐一族!你是否也是网瘾少年! 来玩体感贪吃蛇吧!只需要电脑上有摄像头就可以玩体感游戏啦~远离屏幕,扭 ...

  3. 阅读笔记11-孤独后厂村:30万互联网人跳不出的中国硅谷

    先看看文章中的几个故事吧: 1.背不出门的LV 林晓冉不敢背着LV去后厂村上班.那个9000块的白棋盘包是她一年前在意大利旅游时买的,同去的朋友在LV店里忙着抢购,纷纷劝她也买一个.她架不住劝,买下了 ...

  4. 孤独后厂村,码农的故乡:30万互联网人跳不出的中国硅谷

    本文来源公众号GQ报道(GQREPORT),更多独家报道请关注GQ报道 采访.撰文:洪蔚琳 编辑:何瑫 北京北五环外,一块叫作后厂村的2.6平方公里的土地被誉为"中国硅谷".这个远 ...

  5. 孤独后厂村,IT人百态:30万互联网人跳不出的中国硅谷

    本文经授权转载自微信公众号:GQ报道 公众号ID:GQREPORT 采访.撰文:洪蔚琳 编辑:何瑫 北京北五环外,一块叫作后厂村的2.6平方公里的土地被誉为"中国硅谷".这个远离北 ...

  6. 一图看完北京互联网公司分布!中关村、后厂村、望京互联网公司扎堆圣地。

    中关村.后厂村.望京几乎国内的知名公司都会在北京这几个地区作为总部. 之所以中关村.后厂村.望京一带能成为互联网公司聚集地,主要还是取决于北京的各类资源分配. <北京互联网公司分布>伯马遇 ...

  7. 编辑部的故事:后厂村有没有生活?

    郑州×××医院:https://yyk.familydoctor.com.cn/12248/郑州×××医院×××:https://yyk.familydoctor.com.cn/12248/郑州××× ...

  8. 探寻后厂村网红联想来酷无人店背后的技术

    0.2秒完成刷脸,便捷的无购物通道,虽然不是第一次体验无人便利店,但联想来酷无人店的用户体验还是超出不少参观人士的预期. 来酷无人店位于联想总部东区一层.在互联网巨头扎堆的后厂村路,来酷是第一家24小 ...

  9. 走近北京后厂村程序员的真实生活:“拿命换钱”

    北京的西北角是个特别的区域,这里汇集了众多互联网及IT企业,实力雄厚的上市公司将自家logo悬挂在大厦的顶端,而刚起步的创业公司也会选择在这里租下一亩三分地. 中关村.上地.西二旗.后厂村--它们成为 ...

最新文章

  1. 调用.NET XML Web Services返回数据集合一
  2. mysql存储过程中文乱码_mysql存储过程碰到中文乱码问题
  3. matlab 变长参数,变长参数函数的概念
  4. 应用计算机金融 pdf,金融保险计算机技术及其在金融业中的应用.pdf
  5. 原python实现素数判断_Python实现求最大公约数及判断素数的方法
  6. activity 流程编辑器_最好用的流程编辑器bpmnjs系列之Viewer
  7. php 跨域 session,php session 跨域的解决办法
  8. 电感电容阻抗和公式记录
  9. python中的join是什么意思_python里join是什么意思
  10. DNS-over-HTTPS(DoH)简析与配置
  11. 云阶月地,关锁千重(一.独享锁/共享锁)
  12. 使用Python Openssl库解析X509证书信息
  13. python考证书-Python全国二级等级考试(2019)
  14. 黑龙江省谷歌地球高程DEM等高线下载
  15. html实现纸张撕边效果,如何打造纸张撕裂效果!(ps教程)
  16. 【go】结合一个go开源项目分析谷歌浏览器cookie为什么不安全 附go项目导包失败怎么解决教程
  17. cad自定义菜单cui_AutoCAD.NET二次开发:创建自定义菜单
  18. 「boomyao」的求职简历(web前端)
  19. 在添加页眉时 图片没有显示
  20. qt中出现out-of-line definition of 'Widget' does not match any declaration in 'Widget'问题的解决

热门文章

  1. (转)戴尔Dell服务器远程管理卡的配置和应用
  2. vue v-bind=“$attrs“、v-on=“$listeners“
  3. 曾红极一时的《弹弹堂》真的已经凉了吗?
  4. 期权实战交易最重要的经验
  5. 微云CEO刘琦:移动游戏创业成本几乎为零
  6. python移动端爬虫_移动端爬虫工具与方法介绍
  7. 极客日报第124期:脉脉因“App 整改下架”事件致歉;阿里云全年营收超 600 亿;腾讯防大量群消息骚扰专利获授权
  8. 络达开发----如何开启AGC功能
  9. ubuntu开机自动运行.sh文件
  10. 【Linux】Linux最常用的20个基本指令 介绍~分析