项目简介
近年来,随着虚拟现实技术和计算机图形学技术的迅猛发展,越来越多的体感游戏在市场上出现并受到欢迎。要让体感游戏具备良好的表现,就需要使用大量的传感器,甚至需要使用高性能的计算机和图形处理器。这不仅会增加游戏的成本,还会影响游戏的流畅性和操作体验。因此,如何在不使用传感器的情况下,实现高性能的体感游戏开发成为了一个颇具难度的问题。
为了解决这个问题,本文提出了基于关键点检测模型和摄像头的体感游戏开发方案。其中,PP-TinyPose 模型是飞桨推出的人体检测算法,它可以快速、准确地检测出人体关键点,从而实现人体的实时跟踪和动作捕捉。而通过飞桨推理部署工具 FastDeploy,可以将 PP-TinyPose 模型与推理引擎相结合,实现高效的推理部署,从而让游戏可以在仅使用 USB 摄像头的情况下,流畅地运行在一般电脑上。
当前已经开发完毕的小游戏包括
详细信息:
使用 FastDeploy 调用 PP-TinyPose 的优势:
import fastdeploy
import cv2
model=fastdeploy.vision.keypointdetection.PPTinyPose( 'PP_TinyPose_128x96_infer/model.pdmodel', 'PP_TinyPose_128x96_infer/model.pdiparams', 'PP_TinyPose_128x96_infer/infer_cfg.yml')
img = cv2.imread( 'test.jpg')
result = model.predict(img)
后端
通过 PyQt5 创建前端页面,初始化需4个部分
游戏管理器初始化:用于创建游戏变量
设备初始化:开启摄像头
class Window(QWidget):
def __init__(self):
super().__init_ _()
self.game_obj = GameObject()
self.keypoints = None
self.initModel()
self.initCamera()
self.initClock()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
self.Game_Box = QLabel() # 定义显示视频的Label
self.Game_Box.setFixedSize( 500, 500)
grid.addWidget( self.Game_Box, 0, 0, 20, 20)
self.Game_Box.setMouseTracking(True)
self.Pred_Box = QLabel() # 定义显示视频的Label
self.Pred_Box.setFixedSize( 500, 500)
grid.addWidget( self.Pred_Box, 0, 20, 20, 20)
self.setWindowTitle( 'test')
self.show()
def initClock(self):
# 通过定时器读取数据
self.flush_clock = QTimer() # 定义定时器,用于控制显示视频的帧率
self.flush_clock.start( 30) # 定时器开始计时30ms,结果是每过30ms从摄像头中取一帧显示
self.flush_clock.timeout.connect( self.updata_frame) # 若定时器结束,show_frame()
def initCamera(self):
# 开启视频通道
self.camera_id = 0 # 为0时表示视频流来自摄像头
self.camera = cv2.VideoCapture() # 视频流
self.camera.open( self.camera_id)
def initModel(self):
self.model = fastdeploy.vision.keypointdetection.PPTinyPose( '../../Models/PP_TinyPose_128x96_infer/model.pdmodel', '../../Models/PP_TinyPose_128x96_infer/model.pdiparams', '../../Models/PP_TinyPose_128x96_infer/infer_cfg.yml')
在周期性调用函数中,需要完成以下操作体系
读取图片进行推理
展示画面
def inferModel(self):
# read pic from camera
_, img = self.camera.read() # 从视频流中读取
img = cv2.flip(img, 1) # 摄像头画面反转
img2 = cv2.resize(img, ( 500, 500)) # 把读到的帧的大小重新设置为 640x480
showPic = QImage(img2, img2.shape[ 1], img2.shape[ 0], QImage.Format_BGR888)
self.Pred_Box.setPixmap(QPixmap.fromImage(showPic))
try:
result = self.model.predict(img)
self.keypoints = result.keypoints
showPic = QImage(img, img.shape[ 1], img.shape[ 0], QImage.Format_BGR888)
self.Pred_Box.setPixmap(QPixmap.fromImage(showPic))
except:
pass
def updata_frame(self):
self.inferModel() # infer and show
# update balance
self.game_obj.update( self.keypoints)
# 绘制游戏窗口
img = self.game_obj.draw_canvas()
showPic = QImage(img, 500, 500, QImage.Format_BGR888)
self.Game_Box.setPixmap(QPixmap.fromImage(showPic))
# 游戏结束
state, score = self.game_obj.get_game_state()
if state: # 游戏结束
QMessageBox.information( self,
"Oops!",
"游戏结束!\n您的分数是" + str(score),
QMessageBox.Yes)
self.game_obj.__init_ _()
class GameObject(object):
def __init__(self):
self.x = 100
self.y = 100
self.score = 0
def update(self, keypoints):
self.x = keypoints[ 9][ 0]
self.y = keypoints[ 9][ 1]
def get_game_state(self):
game_status = False
if self.x > 250:
game_status = True
return game_status, self.score
def draw_canvas(self):
# draw balance
img = np.ones([ 500, 500, 3]).astype( 'uint8') * 255
cv2.circle(img, (int( self.x), int( self.y)), 5, ( 255, 0, 0), 3) # draw circle
return img
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Window()
sys. exit(app.exec_())