赞
踩
在游戏的脚本类辅助中,避免不了一个功能,那就是找图返回图像在屏幕上的坐标,对于找图功能,现成的方法,现成的脚本工具数不胜数,但是至于精度那就不好说了。举个现成方法的例子,在python自动化中,pyautogui有个方法为locateOnScreen(image="图片路径"),其作用为在桌面上找到路径中设置的图片,并返回坐标元组,这个方法能找到图的前提是所传路径图和桌面图完全一致,即必须100%匹配,这是一个缺点也是优点,例如找桌面图标,我图标换个地方摆,它可能就找不到了,因为背景变了。另外举个现成工具例子,在按键精灵中自带找图功能,而且很方便,一般的找图完全适用,且可以设置图像匹配率,但是在某些情况下他还是无法胜任,也是因为某些游戏背景是处于一个动态变换的原因。这里分享一个通过python完成一个可多参数控制的识图功能。
不要怕,最后我会将自己封装的工具方法发出来,直接复制粘贴传参就行,要传的参数见下方可控参数。
本文章的图像识别主要用到的是基于SIFT检测算法,在图像识别这块,浅度的识别比较知名的有SIFT、SURF、ORB,而SIFT是精度最高的一种,他能在不同尺度、旋转、光照变化和视角变化的情况下都能保持较好的检测性能。
max_init_num:最大搜索系数,范围0.1~1,系数越小精度越高,建议不要高于0.5(我给你建议那就是因为自己测试过),当然我们这里会做成一个从0.1循环搜索图片,自增到我们设置的最大系数。
trees:索引树数量,数量越大,精度越高,但相应的耗时越高,建议100
checks:索引树遍历次数,数量越大,精度越高,但相应耗时越高,建议1000
img_url:即要匹配的图像的路径(注意路径不可含有中文,图片名也不可含有中文)
即在屏幕上找到我们期望的图片,并返回位置信息
- import os
- import cv2
- import pyautogui
因为是要在屏幕找图,所以直接用pyautogui直接全屏截图对比即可,截下来的图会自动保存到当前目录,最后面用os删掉就行了
语句解释:通过screenshot截取了全屏图片命名为screen.png并放在当前目录下,然后通过cv2.imread分别读取截取的屏幕图的图像数据和我们期望寻找的图像的数据,返回的数据是一个numpy数组,若为彩色图像则是一个三维的numpy数组。
- pyautogui.screenshot(imageFilename="screen.png")
- screenPic=cv2.imread("screen.png")
- img_url=r"C:\testpic\wx.png"
- myPic=cv2.imread(img_url)
要获取图像的关键点和描述符就需要SIFT对象,通过cv2创建即可,然后经过sift对象的检测和计算获取到两张图的监测点和描述符。
- sift=cv2.SIFT_create()
- screenPicKP,screenPicDES=sift.detectAndCompute(screenPic,None)
- myPicKP,myPicDES=sift.detectAndCompute(myPic,None)
这里就用到了我们所说的可控参数,索引树数量,索引树遍历次数。
这里我选择了Flann匹配器,因为简单且直接,对于小型数据集或实时应用运算速度较快。
语句解释:
如下indexParams表示定义索引数量,searcheParams表示定义单个索引遍历次数,这两个参数是构成Flann匹配器的基本条件,因此再通过cv2.FlannBasedMatcher传入参数就得到了flann匹配器了。
- trees=100
- checks=1000
- indexParams=dict(algorithm=0,trees=int(trees))
- searcheParams=dict(checks=int(checks))
- flann=cv2.FlannBasedMatcher(indexParams,searcheParams)
解释:调用flann匹配器的knn匹配法,传入两张图的描述符数据,k表示要返回的最近邻的数量。然后通过sorted方法根据描述符中特征点的距离distance进行一个排序,因为后面会取中位数作为最优匹配
- matches=flann.knnMatch(screenPicDES,myPicDES,k=2)
- matches=sorted(matches,key=lambda x:x[0].distance)
解释:
x,y用于存放最后找到图返回的坐标,没找到就是None
max_init_num是我们的可控参数,表示期望最大的匹配率,建议0.3~0.5,过小会找不到,过大会找错。
如下定义的循环条件是当初始匹配系数小于我们设置的最大系数时,就不断进行循环查找最优匹配并填充坐标值
最后我们通过os移除了截屏的图片
- x, y = None, None
- max_init_num=0.4
- init_num=0.1
- init_num=float(init_num)
- while init_num<=max_init_num:
- goodMatches=[]
- for m,n in matches:
- if m.distance<init_num*n.distance:
- goodMatches.append(m)
- index=int(len(goodMatches)/2)
- try:
- x,y=screenPicKP[goodMatches[index].queryIdx].pt
- break
- except:
- init_num=init_num+0.1
- os.remove("screen.png")
- print("图像在屏幕上的x坐标为:"+str(x))
- print("图像在屏幕上的y坐标为:"+str(y))
首先测试能否找图,可以看到找到图并获取到了坐标,然后用pyautogui.moveTo将鼠标自动移上去了。
我向图片添加了三次马赛克进行了模糊处理,这种识图方法依旧能够识别到,可见其识别能力还是很不错的,这里用的最大搜索系数为0.1
- import os
- import cv2
- import pyautogui
-
- """
- 全屏幕找图,返回图坐标x,y,没找到图则返回None,None
- max_init_num:最大搜索系数,0.1~1.0,越低越精确,建议不要高于0.5,
- trees:索引树数量,建议100
- checks:索引树遍历次数,建议1000
- img_url:要找的图的文件路径(路径不能含有中文,图片名不能含有有中文)
- """
- def FindImgOnScreen(max_init_num,trees,checks,img_url):
- init_num=0.1
- #截取屏幕图
- pyautogui.screenshot(imageFilename="screen.png")
- #读取屏幕图
- screenPic=cv2.imread("screen.png")
- #要匹配的图
- myPic=cv2.imread(img_url)
-
- #获取两图关键点和描述符
- sift=cv2.SIFT_create()
- screenPicKP,screenPicDES=sift.detectAndCompute(screenPic,None)
- myPicKP,myPicDES=sift.detectAndCompute(myPic,None)
-
- #获取FLANN匹配器
- indexParams=dict(algorithm=0,trees=int(trees))
- searcheParams=dict(checks=int(checks))
- flann=cv2.FlannBasedMatcher(indexParams,searcheParams)
-
- #FLANN匹配器进行KNN匹配
- matches=flann.knnMatch(screenPicDES,myPicDES,k=2)
- #根据描述符距离排序
- matches=sorted(matches,key=lambda x:x[0].distance)
-
-
- #筛选优秀匹配
- x, y = None, None
- init_num=float(init_num)
- while init_num<=max_init_num:
- goodMatches=[]
- for m,n in matches:
- if m.distance<init_num*n.distance:
- goodMatches.append(m)
- #获取最佳坐标
- index=int(len(goodMatches)/2)
- try:
- x,y=screenPicKP[goodMatches[index].queryIdx].pt
- return x,y
- except:
- init_num=init_num+0.1
-
- os.remove("screen.png")
- return x,y
源码资源尽在https://www.tbszyw.com
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。