用OpenCV玩《铁拳》!!!
共 5849字,需浏览 12分钟
·
2021-04-25 10:25
点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达
用手势导航可以完成GTAV,那么这一思想也能带入到别的游戏中。因此,我们的第一选择是打格斗游戏,并且该类别中最好的游戏之一是《铁拳》(SFTK)。主要概念很简单,无论人类玩家会采取什么行动(例如拳打),游戏中的玩家都会复制相同的动作。因此,为了实现这个想法,我们想出了两种方法。
首先,一种是较为复杂的方法:把我们的200+图像做不同的动作(如冲压,跳跃)等,然后用它来训练模型,以不同的姿势或者动作之间进行分类,并模拟它在游戏。但是这种方法存在一些问题。
显而易见,我们必须给自己拍很多张照片,每个类别中要有200张以上。这将非常忙碌,并且为了概括起见,我们还需要不同大小,背景和光照条件不同的人的图像。这可能会花费很多时间。
第二种方法是简单地使用我们以前在Virtual Switch and Gesture Gaming中的项目中的想法,为了概念验证,我们决定采用第二种方法。
其工作背后的主要概念非常容易,只是有一个虚拟开关,只要按下该开关,就可以模拟游戏中相应的动作(踢)。
跟踪脸部。
将边界框wrt移到bbox面。
使用特定区域作为专用于特定操作的虚拟交换机。
Bbox(边界框)是用于指代感兴趣区域(矩形/框内)的术语。
我们跟踪人脸,并且虚拟开关框相对于人脸移动。因此,为了在游戏中移动而使用的逻辑是:
当我们前进一定的门槛时,玩家也将开始前进,反之亦然。 我们存储一条穿过脸部中心的水平线。如果我们跳跃并越过中心线一个阈值,则玩家也会跳跃。同样,当我们走到线下时,玩家将蹲下。
在此笔记本中,我们将定义人类玩家开始的初始位置。因此,将通过跟踪算法从该位置跟踪他。首先,设置相机并将其放置在固定位置。然后,我们将只跟踪面部来跟踪人类玩家在游戏中的位置,因此执行“面部”框单元格,然后:
从开始的位置做准备。 计时器结束后,在脸部周围放置一个bbox。
现在,如果您还想为新操作添加新的开关,则可以运行“按钮”单元,然后:
设置n。这是总数。要添加的开关数量。 保持脸部收件箱为准,并进行操作(例如踢)。然后在您要分配用于踢脚动作的区域周围打一个方框。 要保存以供以后使用,请复制打印的输出并将其粘贴到Switch.py上。
请注意,开关0将映射到操作键0。因此,将操作映射到类Action中的键。
class Buttons:
def __init__(self, n=0, bbox_body=(), training=False):
self.training = training
if not training: # automatically set the buttons values if not training mode
self.set_buttons()
else:
self.n = n
self.bbox_switch = []
self.bbox_body = bbox_body
self.center_point = get_centroid(self.bbox_body) # center point of face
self.buttons_bbox_init()
self.action = Actions(self.center_point) # calling the Actions object
def set_buttons(self):
self.bbox_body, self.center_point, self.n, self.bbox_switch = buttons_data
def buttons_bbox_init(self): # to setup the regions of action (bbox of switch)
self.switches = [] # the switch object
self.bbox_center = [] # the coordinates of bbox of switch wrt to the face
for i in range(self.n):
if not self.training: # copy the switch data, if already done the setup
bbox = self.bbox_switch[i]
s = Switch(self.bbox_body, bbox)
else: # else, select the region for switch
s = Switch(self.bbox_body)
self.bbox_switch.append(s.bbox)
self.switches.append(s)
self.bbox_center.append(self.bbox_wrt_center(s.bbox)) #now bbox is wrt origin
if self.training: # prints the values of bbox of body and switch
print(f'bbox_body = {self.bbox_body} \nbbox_switch = {self.bbox_switch}')
# Calculates the distance of bbox from center point (face). Then this is used to get new position
# of switch when the positoin of face changes.
def bbox_wrt_center(self, bbox):
center_x, center_y = self.center_point #starting center point, find switch pos, wrt starting bbox
x, y, w, h = bbox
dx, dy = x - center_x, y - center_y
return dx, dy, w, h
# updates to the new position of bbox switch, wrt to face
def bbox_update(self, bbox):
curr_x, curr_y = self.curr_center #cetner curr point of body
dx, dy, w, h = bbox
x = dx + curr_x
y = dy + curr_y
return x, y, w, h
def run(self, frame, curr_center):
self.curr_center = curr_center
for i in range(self.n):
s, bbox = self.switches[i], self.bbox_center[i]
s.bbox = self.bbox_update(bbox)
pressed = s.update(frame)
if pressed:
self.action.press_val(i)
self.action.action_movement(curr_center)
我们将初始化按钮对象,其中将包含所有虚拟交换机,通过训练为False将使其使用默认值。
button = Buttons(training=False)
tracker = cv2.TrackerCSRT_create()
fvs = cv2.VideoCapture(path)
TIMER_SETUP = 3
t = time.time()
while True:
frame = get_framecv2(fvs)
curr = (time.time() - t)
if curr > TIMER_SETUP or frame is None:
break
cv2.putText(frame, str(int(TIMER_SETUP - curr)+1), (225,255), cv2.FONT_HERSHEY_SIMPLEX, 1.5, COLOR_RED, 4)
cv2.putText(frame, 'Keep your face inside the box', POS_SCREEN, cv2.FONT_HERSHEY_SIMPLEX, 1, COLOR_RED, 4)
drawbox(True, bbox, frame)
cv2.imshow("Tracking", frame)
cv2.waitKey(1)
tracker.init(frame, BB)
#After the timer finishes, now your actions will be recorded, and will be mapped to key in game.
while True:
frame = get_framecv2(fvs)
if frame is None:
break
copy = frame.copy()
_, bbox = tracker.update(frame)
drawbox(True, bbox, frame)
button.run(frame, get_centroid(bbox))
cv2.imshow("Tracking", frame) # orig video frames
k = cv2.waitKey(1)
if k == 13: #13 is the Enter Key
break
cv2.destroyAllWindows()
fvs.release()
唯一的变化是,我们将当前帧传递给button对象,该对象将跟踪位置的变化以及与所按下的虚拟开关相对应的游戏中要执行的动作。
该脚本包含所有基本功能,交换机—此类用于实现虚拟交换机。
按钮-此类用于:
存储所有Switch对象 通过当前帧来决定要按下哪个开关。
bbox_wrt_center:此函数用于计算开关wrt到脸部中心的坐标。这样做是为了在我们移动时,开关也相应地移动。运行—此功能获取当前帧,并将其传递到开关。如果按下任何开关(返回True),则在游戏中按下与该开关相对应的动作。
动作:此类用于将Switch与游戏中相应的动作键(打孔,向左移动)映射。注意—我们尚未在其他PC上进行过测试,因此,如果某项操作在您的PC上不起作用,请尝试为Pressley和ReleaseKey之间的时间间隔设置不同的值。
注意:
确保视频质量良好并且光线充足。由于它是通过计算噪声来工作的,因此低图像质量或低光照可能会导致某些异常。 您可以使用背景减法器的history参数,并根据需要更改开关的阈值。
因此,这是我们尝试使用图像处理技能来创建一种有趣的玩《铁拳》游戏的方法。这只是对该想法的实验,将来,我们可能会使用一些更好的技术来获得更好的结果。
交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~