我需要从简单的游戏 Chrome Dyno 检测图像上的对象。我正在使用 Python 和 Selenium 启动游戏,并加载 Canvas Image。主要任务,它检测此图像上的对象并找到 Dyno 和 Dyno Barriers。
我正在使用此代码,使用 OpenCV 解析图片上的所有对象,cv2
图书馆。
在此代码下方(两个主要功能),识别所有对象需要大约 80 - 200 毫秒(基于障碍大小)。
`
# Finding only dino object based on Template.
# This might be optimized later with searching by contours
def find_dino__(self, cv2_image):
result = cv2.matchTemplate(cv2_image.astype(np.uint8), self.dino_image, cv2.TM_CCOEFF)
_, _, _, dino_top_left = cv2.minMaxLoc(result)
dino_bottom_right = (dino_top_left[0] + self.dino_width, dino_top_left[1] + self.dino_height)
return GenericGameObject(dino_top_left, dino_bottom_right)
# Find other Barrier Objects, based on position, and except
# that, which behind Dino location. Use Dino position.
def find_dino_barriers__(self, cv2_image, dino_object):
img_fil = cv2.medianBlur(cv2.cvtColor(cv2_image, cv2.COLOR_BGR2GRAY), 13)
img_th = cv2.adaptiveThreshold(img_fil, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
im2, contours, hierarchy = cv2.findContours(img_th, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
objects = []
for i in range(len(contours)):
x, y, w, h = cv2.boundingRect(contours[i])
if y < Settings.DINO_WORKING_Y_AREA[0] \
or y > Settings.DINO_WORKING_Y_AREA[1]:
continue
if x <= dino_object.top_right_point[0]\
and y <= dino_object.top_right_point[1]:
continue
objects.append(GenericGameObject((x, y), (x + w, y + h)))
return objects
`
我的目标是减少这个时间 ,尽可能使游戏可用于其他脚本。顺便说一句,我启发了 IAMDinosaur 项目,其中使用 JS 和 Robot JS 完成了这项任务。
最佳答案
有助于提高速度的三大建议都归结为同一件事:将图像的不同部分拆分为处理管道的不同部分。通过寻找不同的对象可以获得额外的加速。这两个目标是找到恐龙位置,以及找到图像中新物体的位置。
加速1
删除霸王龙和物体不在的图像部分。我的意思是框架的上半部分(ish)。对象不在此处,这大大减少了搜索空间。
加速2
我在您帖子的评论中提到了这一点。不要在整个框架中寻找霸王龙。您知道霸王龙会在画面中的某些水平边界内停留,并且只能垂直移动。模板匹配绝对是一个缓慢的过程,因此您将通过减少搜索区域获得很大的加速。您可以通过使用更小的模板和更小的搜索区域来进一步细化。同样,您知道霸王龙将在某个部分,这意味着您知道霸王龙的头部或尾部将位于某个较小的区域——因此在该区域搜索头部或尾部或任何其他内容。您可以通过将搜索区域缩小到它在最后一帧中的位置来进一步细化。我是这样做的 tracking Mario例如;您可以看到白色的搜索区域框,它会在最后一帧中马里奥的头部所在的位置移动。
加速3
请注意,您只需要找到新对象...您知道滚动的速度,因此您知道一旦检测到对象移动的速度以及它们在下一帧中的位置。对象不是整个框架的宽度,它们一次只占框架的一部分。因此,实际上您只需要搜索从屏幕右侧进入的新对象。然后你可以标记它们(它们的宽度、高度、位置)并在此之后计算它们的位置,而不是每帧再次找到它们。现在,您的轮廓搜索仅发生在较小的帧子集中(更快),并且您循环遍历的轮廓更少(更快)。
加速4
请注意,您可以简单地通过“地面”线下方的仙人掌底部来检测仙人掌。看起来相似高度的仙人掌具有相似的宽度,所以如果你检测到一个块,比如 4 像素宽,你就会知道仙人掌实际上在两侧延伸了 8 像素,高 30 像素,或者不管实际值是什么。这会将您的问题变成检测仙人掌的基部而不是完整的仙人掌,并极大地减少了仙人掌的搜索区域。此外,您甚至不需要使用这种方法找到轮廓!您可以简单地查找图像底部的块,并在它们相距小于某个预定义距离时将它们组合在一起。这应该更快。如果你这样做,你可能不需要担心只检测右边界的对象,然后计算它们在新帧中的新位置......如果你只为它们查看 4px 宽的 strip ,那就是可能不会比每帧找到它们快多少。
其他建议
我真的不明白模糊和自适应阈值的意义。图像实际上已经是二进制的;黑色或非黑色像素。也许这是一种将多个单独的对象(如单个仙人掌)组合成一个组的方法?无论哪种方式,都可能有更好(更快)的方法来做到这一点;例如,如果您腐 eclipse 了图像(这会扩大暗像素),那么仙人掌会合并。我认为这会更快,但您需要进行测试。如果你这样做了,你的轮廓就会比它们的实际宽度大一点,但是你可以通过使边界框缩小多少像素来进行补偿。当然,如果您实现加速 4,这并不重要,但这是需要考虑的。
关于Python - 解析图像上的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46061089/