一、说明
根据项目需求,最近在做一些技术研究相关的工作,主要是:实时获取游戏比赛视频中每个角色的 血量大小,以及对应角色的名字,以便于对游戏中角色情况进行实时检测,从而实时预测游戏战况。
由于比赛的源数据,在游戏开发商手中,比如:和平精英游戏由某讯开发,要想拿到他们的数据是相当困难的。
而我们能做的,就是截取比赛视频上的图片,从而对截取的图片进行检测
二、 既然是研究性工作,当然我们也是想了几种实现方案的
方案一:我们通过YOLO训练识别建立模型库,找到我们要使用的数据,并对它进行识别,如下图:
YOLO(You Only Look Once)是一种基于深度神经网络的对象识别和定位算法,其最大的特点是运行速度很快,可以用于实时系统
对于图片上的信息,我们可以通过OCR 来识别名字,但是对于白色的识别,我们遇到麻烦了,看到这里的小伙伴说,可以通过二值化处理啊,把白色的区域给检测出来,但是请看下图:
对于图片上这种情况,二值化方案不是一个好的方式,在游戏比赛过程中,这种重叠的情况并不少见,而且有时候,名字都无法识别出来,所以这种方案是不利于我们 实时检测数据的,那么我们来看看方案二
方案二:请先看下图:
经常玩游戏或者喜欢打终端游戏的小伙伴,对这个界面一定不陌生,这个视图是固定在左上角的,我们可以实时获取这个视图,并对它的名字和血量进行识别,由于随着血量的消耗,选手血量的颜色会有所不同,我们需要提前获取要检测目标区域的颜色,然后在计算出目标区域的大小。
获取图片的颜色:
#获取检测目标的BGR值
def getTargetColor(img):
imgShape = img.shape
# 获取像素坐标(5,H/2)的BGR值
imgHeightHalf = int(imgShape[0]/2)
BGR = np.array([img[imgHeightHalf][5][0], img[imgHeightHalf][5][1], img[imgHeightHalf][5][2]])
print(BGR)
return BGR
但是,由于血量在变成粉红色或者灰色的时候,不是一个纯色(半透明色),会和后面的颜色进行融合,会导致,我们在做指定区域颜色识别的时候存在一定误差,为了,可以让我们识别的区域更准确,我们可以指定一个颜色的范围 ,由于检测返回的是区域边缘的坐标,我们可以找出X 方向最大的值和X 方向最小的值,从而确定目标区域的长度,也就是血量的大小,由于我们截图的时候知道总的血量的大小,从而知道某个选手,剩余血量的百分比,以及当前的状态
以下是核心代码:
#获取血液剩余的百分比
def getPercentageOfBloodVolume(BGR,img):
B = int(BGR[0])
G = int(BGR[1])
R = int(BGR[2])
# 寻找合适的上浮范围 不得使 RGB 值高于 255
upRange = 20
if 255 - B < upRange:
upRange = 255 - B
if 255 - G < upRange:
upRange = 255 - G
if 255 - R < upRange:
upRange = 255 - R
#寻找合适的下浮范围值 不得使 RGB 值低于 0
lowRange = 40
if B - lowRange < 0:
lowRange = B
if G - lowRange < 0:
lowRange = G
if R - lowRange < 0:
lowRange = R
# print('upRange == ',upRange)
# print('lowRange ==',lowRange)
upper = BGR + upRange
lower = BGR - lowRange
# 确定要检测的颜色范围
mask = cv.inRange(img, lower, upper)
(contours, hierarchy) = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
print('number of countours: %d' % (len(contours)))
#================================= 测试检测范围的代码 =============================
# 找到绘画轮廓 水平方向最大值
originXMax = 0
for pointArray in contours:
for x in pointArray:
for y in x:
for originX in y:
if originXMax < originX:
originXMax = originX
print('originXMax == ', originXMax)
# 根据图片的大小判断,目前血量所占的 百分比
imgShape = img.shape
imgWidth = imgShape[1]
bloodPer = originXMax / (imgWidth - 2)
bloodPer = format(bloodPer, '.2f')
return bloodPer
这里需要注意的是:在取值颜色范围的时候,BGR 范围取值要控制在 0 ~ 255 ,否则结果会出问题
三、总结
由于是研究性工作,这其中也遇到了很多问题和困难,不过都一一解决了,这其中也包含,怎么对文字的准确识别,以及如何矫正错误名字识别,这里暂时不过多言表,写这篇文章,一是做下记录,二是给有相似需求的小伙伴做个参考