Python辅助-找图功能(你还在用pyautogui?)

前言

在游戏的脚本类辅助中,避免不了一个功能,那就是找图返回图像在屏幕上的坐标,对于找图功能,现成的方法,现成的脚本工具数不胜数,但是至于精度那就不好说了。举个现成方法的例子,在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:即要匹配的图像的路径(注意路径不可含有中文,图片名也不可含有中文)

功能目的

即在屏幕上找到我们期望的图片,并返回位置信息

所需库

arduino 复制代码
import os
import cv2
import pyautogui

正文

第一步:获取两张图片数据

因为是要在屏幕找图,所以直接用pyautogui直接全屏截图对比即可,截下来的图会自动保存到当前目录,最后面用os删掉就行了

语句解释:通过screenshot截取了全屏图片命名为screen.png并放在当前目录下,然后通过cv2.imread分别读取截取的屏幕图的图像数据和我们期望寻找的图像的数据,返回的数据是一个numpy数组,若为彩色图像则是一个三维的numpy数组。

python 复制代码
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对象的检测和计算获取到两张图的监测点和描述符。

ini 复制代码
sift=cv2.SIFT_create()
screenPicKP,screenPicDES=sift.detectAndCompute(screenPic,None)
myPicKP,myPicDES=sift.detectAndCompute(myPic,None)

第三步:准备匹配器

这里就用到了我们所说的可控参数,索引树数量,索引树遍历次数。

这里我选择了Flann匹配器,因为简单且直接,对于小型数据集或实时应用运算速度较快。

语句解释:

如下indexParams表示定义索引数量,searcheParams表示定义单个索引遍历次数,这两个参数是构成Flann匹配器的基本条件,因此再通过cv2.FlannBasedMatcher传入参数就得到了flann匹配器了。

ini 复制代码
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进行一个排序,因为后面会取中位数作为最优匹配

ini 复制代码
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移除了截屏的图片

ini 复制代码
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

​编辑

封装为方法:

ini 复制代码
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

免费源码分享

免费源码资源尽在土拨鼠资源网tbs123.xyz

相关推荐
databook13 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar14 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户83562907805115 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_15 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机21 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机1 天前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i1 天前
drf初步梳理
python·django
每日AI新事件1 天前
python的异步函数
python