译者最后更新:2022/05/17
dbgba更新:2024/04/11 将代码的英文注释内容,翻译成中文
原文链接:https://www.autohotkey.com/boards/viewtopic.php?f=7&p=456845#p456845
非常感谢用户 feiyue 创建了 FindText,另外也感谢用户 ed1chandler 和 c4p,他们的基础教程让我受益非浅。
【中文版地址】FindText 库的链接:viewtopic.php?f=6&t=17834
简介
FindText 是一个 AHK 库,可以替代内置的 ImageSearch 功能,并包含许多附加功能。FindText 主要用于在屏幕上快速查找图形(图像),其匹配精度比 ImageSearch 高。它将屏幕上抓取一个小图像转换成黑白图像(类似于 ASCII 艺术),然后再将黑白图像转换成单行文本。使用 FindText 时,它会截取屏幕截图,将屏幕截图中的每个像素也转换成黑白,然后尝试将抓取的图像与屏幕截图进行匹配。由于像素变成了黑白,要比较的次数要少得多(红、绿、蓝需要比较三次、黑白只需要比较一次),所以匹配速度要比 ImageSearch 快。
FindText 的一些优点:
1)它不需要图像文件,而是使用图像的文本表示。该函数将屏幕的图像抽象为具有代表意义的“0”(“0”=黑色像素=文本像素)和“_”(“_”=白色像素=背景像素),它们依次排列变成一行数字和字母序列。因为这是一种抽象,而不是逐位比较,所以它可以实现快速匹配及轻松调整容错。
2)它比ImageSearch更快,在我的测试中大概快了10%(在有些用例中甚至可能快2-3倍)。
3)提供了轻松存储及在脚本中获取图像的函数。
4)使用 BindWindow,实现了当窗口藏在其他窗口后面时也能使用 FindText。
5)允许创建简单的自定义 OCR 函数。
目录
(1) 入门
(2) FindText 主要功能
(3) ImageSearch
(4) 什么是Text?
(5) 抓取模式
(6) 辅助函数 Click, MouseTip, RangeTip, ScreenToWindow, ScreenToClient, ClientToScreen, WindowToScreen
(7) 文本库函数 PicLib, PicN, PicX, PicInfo
(8) FindText 组合查找
(9) 光学字符识别 (OCR)
(10) BindWindow
(11) FindTextClass
(12) 截图功能:ScreenShot、GetTextFromScreen、SavePic、ShowPic、ShowScreenShot
(13) 杂项:Sort、Sort2、Sort3、WaitChange
(14) FindText 速度提升技巧
(1) 入门
下载 FindText.ahk 后,我建议将它放在 Lib 文件夹中,然后在自己的脚本中通过以下代码来引入它:
#include <FindText>
做完这些后,你可以使用 FindText().ImageSearch 来替换掉原有的 ImageSearches,从而提升速度,如下所示:
ImageSearch, OutputVarX, OutputVarY, X1, Y1, X2, Y2, ImageFile ; 变成这样 FindText().ImageSearch(OutputVarX , OutputVarY, X1, Y1, X2, Y2, ImageFile)
但是使用 FindText 的推荐方法是:使用 FindText 主函数,并使用文本而非图像文件。为此,先运行 FindText.ahk 脚本,运行后应该会显示出以下 GUI :
看不清楚请在图片上点击右键,选 “在新标签页中打开图片” 查看
中文截图由 AHK1-僵尸 制作提供
按 抓图 按钮 -> 选择要抓取的区域 -> 右键单击两次(第一次右击选择,将鼠标移动到其他位置后再次右击以确认)-> 按灰度阈值二值化按钮 -> 按 确定。如果一切顺利,那么现在按下测试按钮后,FindText 应该会成功找到之前抓取的图像(找到图像的位置会出现一个闪烁的红色框)。
看不清楚请在图片上点击右键,选 “在新标签页中打开图片” 查看
抓取图像后,在下方的文本框会显示一些自动生成的代码,如下所示:
Text:="|<>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330" if (ok:=FindText(X, Y, 312-150000, 79-150000, 312+150000, 79+150000, 0, 0, Text)) { ; FindText().Click(X, Y, "L") } ...
• Text 变量包含文本/字符串形式的图像,以及一些其他必要信息。
• FindText(X, Y, 312-150000, 79-150000, 312+150000, 79+150000, 0, 0, Text) 表示变量 X 和 Y 将被赋值为找到的第一个图像的确切中心的坐标;数字 312 和 79 是最初抓取图像的 x 和 y 坐标,312-150000 和 79-150000 只是搜索区域左上角的一些非常负的 x 和 y 坐标(包括屏幕外的窗口或第二个监视器);312+150000 和 79+150000 是搜索区域右下角的一些非常大的值;0 和 0 是默认误差范围(只允许完全匹配);Text 变量以文本形式为 FindText 提供我们截取的图像。
• 如果删除 FindText().Click 之前的注释符号 (;),则表示在 FindText 成功后,左键单击找到的图像。
接下来的部分将包含一些示例脚本,可以复制粘贴到 FindText main Gui 的示例代码框顶部,然后按 Test 轻松运行这些脚本。将以下图像保存到计算机,并使用 Paint 或其他看图软件打开。在按下 测试 之前确保图片可见,屏幕 DPI 设置为 100%。
(2) FindText 主函数
下面大部分摘自 FindText.ahk 顶部描述区(有一些补充):
returnArray := FindText( OutputX --> 该变量用于存储找到的第一张图片中心的 X 坐标。OutputX 也可以设为"wait"、"wait1" (appear) 或"wait0" (disappear),以使 FindText 要么等待文本出现或消失。如果将 OutputX 留空,则不进行搜索,并返回一个 FindTextClass 实例:在 FindText().Click 示例中使用了这样的代码,等价于 FindText(,,,,,,,,Text).Click (Text 会被忽略)。调用 FindText 执行搜索的最简单形式为 FindText(X,,,,,,,,Text). , OutputY --> 该变量用于存储找到的第一张图片中心的 Y 坐标。如果 OutputX 设为 "wait",则 OutputY 可以设置为等待的秒数,负数表示无限等待。[/list] , X1 --> 搜索区域左上角的 X 坐标 , Y1 --> 搜索区域左上角的 Y 坐标 , X2 --> 搜索区域右下角的 X 坐标 , Y2 --> 搜索区域右下角的 Y 坐标 如果 X1, Y1, X2, Y2 都设为 0 (默认值),则 X1 和 Y1 会被设为 -150000,X2 和 Y2 被设为 150000。这样会将搜索区域设为整个屏幕以及所有不在屏幕上的东西也包括在内。 , err1 --> 文本的容错比例(text=黑色="o")(0.1=10%)。 , err0 --> 背景的容错比例(background=白色="_") (0.1=10%) 如果 err1 和 err0 都为 0,并且没有找到匹配项,则 FindText 会自动使用 0.05=5% 错误容限再次进行搜索。为避免这种情况,可以将 err1 和 err0 指定为很小的一个值(如 0.000001,很接近 0,但是不等于 0)。 , Text --> 可以是多个文本形式的图片,图片之间用 "|" 分隔 , ScreenShot --> 取值为 0 时,使用上一次截屏,默认为 1(每次都重新截屏) , FindAll --> 取值为 0 时,找到第一个结果后立刻返回,默认为 1(查找全部结果) , JoinText --> 用于组合查询:可以是 1,也可以是要查找的单词数组,默认为 0 , offsetX --> 设置组合查找时 X 方向最大文本偏移量 , offsetY --> 设置组合查找时 Y 方向最大文本偏移量 , dir --> 指定搜索方向,共9种取值: 1 ==> ( 从左到右 ) 从上到下 2 ==> ( 从右到左 ) 从上到下 3 ==>(从左到右)从下到上 4 ==>(从右到左)从下到上 5 ==>(从上到下)从左到右 6 ==>(从下到上)从左到右 7 ==>(从上到下)从右到左 8 ==>(从下到上)从右到左 9 ==>从中心向外 )
该函数返回一个包含所有查找结果的二阶数组(returnArray[1] 表示找到的第一个结果,returnArray[2] 表示第二个,...),每个结果都是一个关联数组:{1:X, 2:Y, 3:W, 4:H, x:X+W//2, y:Y+H//2, id:Comment}
如果没有找到图像,则 FindText 返回 0。
例如,如果返回变量的名称是 "ok", 则 ok[1] 表示找到的第一个结果。
ok[1][1] 和 ok[1][2] 是找到的第一个图像的左上角的 X 和 Y 坐标,
ok[1][3] 是找到图像的宽度,而 ok[1][4]是找到图像的高度,
ok[1].x <==> ok[1][1]+ok[1][3]//2 <==> OutputX(找到图像中心的 X 坐标),
ok[1].y <==> ok[1][2]+ok[1][4]//2 <==> OutputY(找到图像中心的 Y坐标 ),
ok[1].id 是注释文本,包含在 Text 的 <> 部分。
如果 OutputX 设置为“wait”、“wait1”(出现)或“wait0”(消失),则出现超时意味着搜索失败并返回 0,其他值表示成功。如果等待“出现”并找到图像,则返回找到的数组对象。如果等待“消失”且找不到图像,则返回 1。
FindText(X:="wait", Y:=3, 0,0,0,0,0,0,Text) ; 等待3秒钟出现 FindText(X:="wait0", Y:=-1, 0,0,0,0,0,0,Text) ; 无限期等待消失
更多注意事项:
• 所有返回的坐标都是相对于屏幕而言的(如在 CoordMode Screen 模式)。要转换为相对坐标,请使用转换函数 ScreenToWindow 和 ScreenToClient。
• 所有颜色均为十六进制 RGB 格式。
• FindText 对屏幕 DPI 敏感,这意味着使用一种 DPI 抓取的图像/文本无法与另一种 DPI 一起使用。为确保用户使用正确的 DPI,请使用内置变量 A_ScreenDPI 进行检查。
• 使用多台显示器时请注意将 X1,Y1,X2,Y2 设为 0,0,A_ScreenWidth,A_ScreenHeight 这一情形,因为此设置只会抓取主显示器。建议将它们留空(默认值 -150000,-150000,150000,150000 应该足够大,可以覆盖所有显示器),或者使用与默认值类似的大值。
对于以下示例,请使用看图软件打开第 1 节中提供的 Examples.png。然后在新脚本中运行代码,或者将#include 行以外的所有代码复制到 FindText Gui 代码框,然后按 Test 按钮进行测试。
示例1:
#include <FindText> ; “autohotkey.com”中“auto”部件的图像。图像的Id为“auto”(介于< and >个字符之间)。 Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" ; 调用FindText查找“自动”图像。outX和outY将被设置为第一个找到的结果的X和Y坐标。搜索范围坐标err1和err0为空,以使用默认值(搜索整个屏幕,并查找完全匹配)。结果将存储在“ok”变量中。 ok := FindText(outX, outY,,,,,,,Text) if ok { ; 检查“ok”是否未设置为0 MsgBox, The image (Text) was first found at coordinates X: %outX% Y: %outY% ; 显示outX 和outY MsgBox, % ok.MaxIndex() " 找到了结果。" ; ok.MaxIndex()和ok.Length()应该返回找到的搜索结果数。 MsgBox, % "第一个找到的图像位于X" ok[1][1] " Y" ok[1][2] ". 它的宽度为" ok[1][3] " 高度为" ok[1][4] ". 此外,它的id为 " ok[1].id if ok[2] ; ok[1]包含第一个结果,ok[2]包含第二个结果,等等。检查ok[2]是否存在,如果存在,则显示其部分内容。 MsgBox, % "找到的第二个图像位于X" ok[2][1] " Y" ok[2][2] " 宽度为 " ok[2][3] " 高度为 " ok[2][4] ". 此外,它还有一个评论文本 " ok[2].id } else { MsgBox, 找不到图像/文本。是否所有设置都正确,并且图像在“绘制”中可见? ; 看起来“ok”是空的,所以什么也没找到。 }
示例2:
#include <FindText> ; 调用FindText查找“自动”图像。outX和outY将被设置为第一个找到的结果的X和Y坐标。搜索范围左上角为(0;0),右下角为(A_ScreenWidth;A_ScreenHeight),应搜索整个屏幕,但如果使用多个监视器,则可能无法正常工作。“1”和“0”的误差幅度都设置为5%。结果将存储在“ok”变量中。如果“ok”包含结果,则“If”条件将成功。 if (ok := FindText(outX, outY, 0, 0, A_ScreenWidth, A_ScreenHeight, 0.05, 0.05, "|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8")) { for k, v in ok { ; 循环显示“ok”中的所有搜索结果。“k”将是第n个结果,“v”将包含结果本身。 MsgBox, % "结果编号 " k " 位于X" v[1] " Y" v[2] " 宽度为 " v[3] " 高度为 " v[4] ". 此外,它还有一个评论文本 " v.id ; v[1]等价于ok[k][1],v.id等价于ok[k].id,依此类推。 } } else { MsgBox, 找不到图像/文本。是否所有设置都正确,并且图像在“绘制”中可见? ; 看起来“ok”是空的,所以什么也没找到。 }
示例3:
#include <FindText> ; “autohotkey.com”中“auto”部件的图像。图像的Id为“auto”(介于< and >个字符之间)。 Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" ; 将“autohotkey.com”中的“hot”部分的图像附加到Text变量(请注意,当我们以前使用“:=”进行设置时,会附加“.=”运算符)。图像的Id为“hot”。 Text.="|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" ; 或者将两个text的内容,写到一个变量里。例如这样: Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" WinGetPos, pX, pY, pW, pH, ahk_class MSPaintApp ; 获取“Paint”应用程序的位置和大小。 ; 调用FindText查找“自动”或“热门”图像。对于第一个找到的结果,X和Y将被设置为X和Y坐标。搜索范围将仅为“绘制”应用程序。将其中一个或两个误差幅度设置为较小的非零值将避免第二次搜索的误差幅度为5%。结果将存储在“ok”变量中。如果“ok”不包含任何内容(“!”是“not”运算符),则退出,否则继续。 if !(ok := FindText(X, Y, pX, pY, pX+pW, pY+pH, 0.000001,, Text)) { MsgBox, 找不到图像/文本。是否所有设置都正确,并且图像在“绘制”中可见? ; 看起来“ok”是空的,所以什么也没找到。 ExitApp } ; 只有当找到任何文本(“hot”或“auto”图像)时,才会发生此部分之后的任何事情。 for key, value in ok { ; 循环显示“ok”中的所有搜索结果。“key”将是第n个结果,“value”将包含结果本身。 FindText().MouseTip(value.x, value.y) ; 在结果的中心显示一个闪烁的红色框。 MsgBox, % "结果编号 " key " 位于X" value[1] " Y" value[2] " 宽度为 " value[3] " 高度为 " value[4] ". 此外,它还有一个评论文本 " value.id ; value[1] 等效于 ok[k][1],value.id 等效于 ok[k].id,依此类推。 if (value.id == "auto") MsgBox, 在这里我们找到了“auto”图像。 }
(3) ImageSearch
FindText().ImageSearch 是 FindText 的包装函数,它更易于使用。它还可以像 AHK 原生函数 ImageSearch 一样接受图像文件(但不支持 *IconN 等选项),并且它支持不同的 CoordMode(FindText 总是返回相对于屏幕的坐标,但 FindText().ImageSearch 可以使用任何一个由 CoordMode Pixel 命令设置的坐标模式,例如 Window 或 Client 坐标模式)。
FindText().ImageSearch(OutputVarX, OutputVarY, X1, Y1, X2, Y2, TextOrImageFile, Screenshot:=1, FindAll:=0)
returnValue := FindText().ImageSearch(
OutputVarX, OutputVarY --> 存储找到图像中心的 X 和 Y 坐标的变量名。除非使用 CoordMode 来更改坐标模式,否则坐标是相对于活动窗口的。
,X1, Y1 --> 搜索矩形左上角的 X 和 Y 坐标。除非使用 CoordMode 来更改坐标,否则坐标是相对于活动窗口的。
,X2, Y2 --> 搜索矩形右下角的 X 和 Y 坐标。除非使用 CoordMode 来更改坐标,否则坐标是相对于活动窗口的。
, TextOrImageFile --> FindText 文本或图像文件的文件名
, Screenshot --> 如果值为 0,则使用最后的截图,默认为 1(每次重新截图)
, FindAll --> 如果值为0,则在找到第一个结果后返回,默认为1(查找所有结果)
)
如果搜索成功,returnValue 将被设置为 1,否则为 0。
如果搜索成功,ErrorLevel 将被设置为 0,否则为 1。
例子:
#include <FindText> if FindText().ImageSearch(X,Y,,,,, A_ScriptDir "\Examples.png") ; 在屏幕上的Examples.png中查找图像 FindText().MouseTip(X, Y) if FindText().ImageSearch(X,Y,,,,, "|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8") ; 查找文本中包含的“auto”图像 FindText().MouseTip(X, Y)
(4) 什么是 Text 文本?
Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" ; 按从左到右顺序:"|" 是分隔符 ; "<auto>" 表示 Text 的 id/comment 为 "auto" ; "*" 是捕获模式,本例中为 Gray ; 159 是灰度阈值 ; 40 (between $ and .) 是原图像的宽度 ; 0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8 是图像的 64-bit 表示
Text 文本字符串由 5 部分组成:
1.竖线字符(|)是图像的分隔符。这意味着可以将多个图像一个接一个地连接在一起,进行同时搜索(或用于组合搜索)。
Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" ; 首先将Text变量设置为包含“auto”图像 Text.="|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" ; 然后使用“.=”运算符将“hot”图像附加到Text变量 ok:=FindText(X,Y,,,,,,,Text) for k, v in ok FindText().MouseTip(v.x, v.y)
等价于以下代码:
Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" ok:=FindText(X,Y,,,,,,,Text) for k, v in ok FindText().MouseTip(v.x, v.y)
并将返回匹配“auto”和“hot”图像的所有结果。
2. <> 字符之间是图像的“id”或“comment”,用于为图像命名。如果 ok:=FindText(...) 成功,则 ok[1].id 将包含找到的第一个图像的 id。id 可以包含任何字母、数字和符号(如果使用 AHK 的 Unicode 版本,则可包括所有 Unicode 字符),">" 和换行符除外。
Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" ; "<auto>" 设置图像 id 为"auto". Text.="|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" ; "<hot>" 设置图像 id 为"hot". ok:=FindText(X,Y,,,,,,,Text) for k, v in ok { ; 遍历所有结果 if v.id == "hot" { ; 只显示结果中 id 为"hot"的图像,忽略其他 id 为 "auto" 的结果 MsgBox, % "The ""hot"" image was found at X:" v.x " Y:" v.y } }
3. > 和 $ 之间的数字和符号将定义用于搜索的模式。有 5 种不同的模式,我们稍后将在“抓取模式”部分中介绍。在“auto”图像的这些示例中,* 表示正在使用 Gray 灰度阈值模式,154 是阈值。
4. $ 和 . 之间的数字是图像的像素宽度。这个数值不应该手动更改,应使用 Cut 按钮进行修改。在第一个示例中,图像“auto”的宽度为 40 像素。
5. 句点(.)之后的所有内容是图像的 64 位文本表示。这里的内容也不应该手动更改,应使用 Cut 按钮进行修改。
6. 有一种在 Text 中包含 err1 和 err0 的非正式方式,它将覆盖传递给 FindText 函数的 err1 和 err0 值。这可以通过在 id 之后添加 [err1,err0] 来完成:
Text:="|<mycomment>[0.2,0.1]*197$15.1U8A11U8C11k8600s0700Q01U004" ; 将err1重写为0.2(20%),将err0重写为0.1(10%) ok:=FindText(X,Y,,,,,0.3,0.3,Text) ; 即使将err1和err0设置为0.3,搜索仍将使用值0.2和0.1
(5) 抓取模式
1. Gray 灰度阈值模式。
在灰度模式下,每个像素的灰度值(取值从 0 到 255,其中 0 为纯黑色,255 为纯白色)将与指定阈值进行比较。如果像素灰度值超过阈值,则将其变为白色(white=background="_"="0"),否则变为黑色(black=text="o"="1")。因此,任何比阈值更暗的像素都变成黑色,而任何比阈值更亮的像素都变成白色。阈值 255 会使整个图像变黑,从而匹配搜索范围内的所有内容。
在 Text 文本的形式中,灰度阈值模式由 * 字符标识,后跟阈值。
Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" ; "<auto>" 之后的 "*" 表示使用的是灰度模式,阈值为 159 (位于 * 和 $ 之间), 图像宽度为 40 像素 (位于 $ 和 . 之间)
2. GrayDiff 灰度差值模式。
每个像素都会被一一考虑到,如果所考虑的像素周围的任一像素的灰度值大于该像素灰度值+阈值(总共比较 8 次),则该像素将变为黑色,否则将变为白色。从本质上讲,它会生成形状的边缘,因为最大的灰度差值出现在边缘等对比度较大的区域,而纯色区域则变为白色。在 Examples.png 的 Gray vs GrayDiff 示例中,如果我们希望 FindText 只找到最右边的 2 个纯色正方形,使用 Gray 模式是无法成功的,但 GrayDiff 却可以把它们成功分离出来(见下面的示例)。
在 Text 文本的形式中,灰度差值模式由 ** 字符标识,后跟阈值。
#include <FindText> Text:="|<solidcolorbox>**50$54.zzzzzzzzzU00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001U00000001zzzzzzzzzU" ; "**" 表示 GrayDiff 模式,阈值设为 50, Text中图像宽度为 54 像素 ok:=FindText(X,Y,,,,,,,Text) for k, v in ok FindText().MouseTip(v.x, v.y)
3. Color 颜色相似模式。
在 FindText Gui 中,单击图像上的某个像素会选择该像素的颜色,并将其定义为“黑色”。然后可以用相似度滑块来包含相似的颜色(相同颜色的阴影),单击颜色相似二值化按钮应用滑块所做的更改。
在 Text 文本的形式中,颜色相似模式由所选颜色的十六进制表示进行标识,后跟@ 和滑块值(相似度取值从 0.00 到 1.00,1.00=100% )。
Text:="|<>505050@1.00$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" ; 只有颜色505050才会被视为文本(黑色像素) ; 相似性设置为1.00(100%),因此只允许按颜色进行精确匹配
4. ColorPos 颜色位置模式。
单击图像上的像素将定义该像素相对于图像左上角的位置,该位置的颜色将用于黑白色的转换。因此,此模式将找到单一颜色的图案,其中颜色取自指定位置的像素。和颜色相似模式一样,该模式也有一个相似度滑块,可以检测相似的颜色。
在 Text 文本的形式中,颜色位置模式由 # 标识,后跟一个数字,该数字是选定的像素位置(从左上角起算,从左到右,然后从上到下),然后是 @ 和滑块值。
Text:="|<>#49@0.90$47.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz07zzzzzy07zzzwDwQ7zzzsTsyDzzzkzlwQ1w007Xsk1k00D7V11127yC2D2DwDw08T47sTs0kyA0kzlzVwQ0VzXz3szV3z7z7VzW7yDy22667wTy0A0A1szy0s0w3zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" ; # 表示 ColorPos 模式 ; 49表示第49个像素(从左到右,从上到下)被视为“黑色”。由于图像宽度为47,因此它是第二行中的第二个像素 ; 0.90为相似性值(90%)
5. ColorDiff 颜色分量模式。
在 FindText Gui 中,单击图像上的像素会选择该像素的颜色,并将其定义为“黑色”。颜色分量二值化按钮将使用所选颜色将图像转换成黑白色。现在,红、绿 和蓝三个输入框可用于选择允许的颜色差异(加或减,但不会从 255 环绕到 0,反之亦然)。例如,如果选择的颜色是 0098D9(十六进制 R=00,G=98,B=D9)并且红输入框设置为 1,那么 FindText 将匹配颜色 0098D9 和 0198D9(但不是 FF98D9-0198D9,因为它不环绕)。然后将绿设置为 5 将匹配 0093D9 和 019DD9 之间的颜色。
Text:="|<>3F627F-00050A$51.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzk1zzzzzzy07zzzwDzlUTzzzVzyD3zzzwDzlwM1s007yDW06000zlsE0EEVzyA0D27wDzk0VsETVzy0ADW0ADzlzVwM0VzyDwD3w4DzlzVsTsVzyDy02467zlzk0k0k7yDz0C0C0zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzw" ; 定义为 "black" 的颜色是 3F627F ; 允许的颜色误差范围为00050A:00(十进制0)表示红色,05(十进制5)表示绿色,0A(十进制10)表示蓝色。
6. MultiColor 多色查找模式。
单击多色查找复选框后,就可以选择多个像素,FindText 将仅在其相对坐标处查找选定的像素(第一个选定像素将位于 x=0、y=0,后面的像素将相对于该坐标),并且只查找选定像素的特定颜色。例如,如果在此模式下选择了两个像素,则 FindText 将仅搜索所选颜色且相对坐标相同的两个像素。RGB 滑块可用于更改误差范围。在Text 文本的形式中,多色查找模式由 ## 标识,后跟一个数字表示 RGB 误差范围 (0-255)。然后在 $ 符号之后,将跟随所选像素的相对坐标和颜色:例如“0/0/3A8000,1/0/008000”表示将搜索颜色为3A8000 和 008000 的两个像素,
多色查找模式也可用于查找文件中的图像。这可以通过指定文件位置而不是单个像素来完成。FindText().ImageSearch 函数在内部使用了此方法。
Text:="|<>##1$0/0/3F627F,-7/1/FFFFFF" ; ## 表示 MultiColor 模式 ; RGB误差范围:1 ; 匹配位置像素颜色为 3F627F (R、G、B 误差范围 ± 1:匹配 3E617E - 406380),第二个像素位置为向左7像素、向下1像素,像素颜色为 FFFFFF (R、G、B 误差范围 ± 1) Text := "|<>##0$" A_ScriptDir "\Example.png" ; 在FindText中使用此Text将在位于脚本目录中的Example.png中查找图像,RGB误差幅度设置为0
(6) 辅助函数 Click、MouseTip、RangeTip、ScreenToWindow、ScreenToClient、ClientToScreen、WindowToScreen
1. FindText().Click(x, y, options)
的参数和 AHK 中的 Click 函数相同,但是在单击期间它将 CoordMode Mouse 设置为 Screen(绝对坐标)。
FindText().Click(100, 200) ; 在屏幕坐标x 100,y 200处单击鼠标左键。
2. FindText().MouseTip(x:="", y:="", w:=10, h:=10, d:=4)
会在指定的 x 和 y 坐标处创建一个闪烁的红色方框,通过直观的显示帮助确认正在使用正确的位置。如有需要,可以更改方框的宽度、高度及其边框的厚度。
FindText().MouseTip(100, 200) ; 在屏幕坐标x 100,y 200处闪烁一个红色方框。
3. FindText().RangeTip(x:="", y:="", w:="", h:="", color:="Red", d:=2)
是 MouseTip 更一般的变体形式,它将显示指定大小、颜色和边框粗细的红色框。请注意,它不会像 MouseTip 那样自动消失。以下示例将在找到的图像边缘周围创建一个闪烁的矩形。
if (ok:=FindText(X,Y,,,,,,,"|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s")) { Loop 4 { FindText().RangeTip(ok[1].1, ok[1].2, ok[1].3, ok[1].4, (A_Index & 1 ? "Red":"Blue"), 4) ; 在找到的图像的边缘显示一个矩形,另外每0.5秒在红色和蓝色之间切换一次颜色。 Sleep, 500 } }
4、ScreenToClient、ScreenToWindow、WindowToScreen、ClientToScreen 在不同 CoordMode 之间转换坐标。
FindText().ScreenToClient(outX, outY, x1, y1, ahk_id:="")
会将 x1 和 y1 从屏幕坐标转换为相对于 id 为 ahk_id 的窗口的客户端坐标,并将 outX 和 outY 设置为获得的结果值。例如,这在使用 ControlClick 时很有用:FindText 将返回相对于屏幕的坐标,但 ControlClick 使用相对于窗口的坐标,因此可以使用 ScreenToWindow。
if (ok:=FindText(X,Y,,,,,,,"|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s")) { FindText().ScreenToWindow(outX, outY, X, Y, WinExist("ahk_class MSPaintApp")) ; 将绝对坐标X和Y转换为相对于“绘制”窗口,结果值将位于outX和outY变量内部 ControlClick, X%outX% Y%outY%, ahk_class MSPaintApp ; 现在单击“绘制”中的坐标 }
FindText().WindowToScreen(outX2, outY2, 200, 300) ; 如果未指定ahk_id,则将使用活动窗口:将相对坐标X200 Y300转换为绝对坐标,并将outX2和outY2设置为结果值。
(7) 文本库函数PicLib、PicN、PicX、PicInfo
1. PicLib 可用于创建图像/文本库,以便使用Text ID(comment)轻松获取文本。
FindText().PicLib(commentOrText, addToLib:=0, libraryIndex:=1)
可以通过将 addToLib 设置为 1 来添加新文本,并且 libraryIndex 可以指定要添加文本的库编号。如果多个 Text 具有相同的 id,则仅添加最后一个。
; 将“auto”文本添加到库1(默认库) FindText().PicLib("|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8", 1) ; 将“hot”文本添加到库2中 FindText().PicLib("|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s",1,2)
可以通过 id 从库中获取文本,此时 addToLib 必须为 0(默认值)。可以同时获取多个id,中间用 | 分隔 (“comment 1|comment2|...”)。
MsgBox, % "Fetching ""auto"" from library 1: " FindText().PicLib("auto") ; 从库1获取id为“auto”的文本 MsgBox, % "Fetching ""hot"" from library 2: " FindText().PicLib("hot",,2) ; 从库2中获取“hot” MsgBox, % "Fetching ""hot"" from library 3: " FindText().PicLib("hot",,3) ; 不返回任何内容,因为“hot”已添加到库2中,而不是库3中
2. PicN(Comment, libraryIndex:=1) 将字符串分解为字符,然后使用 PicLib 获取 Text。这在进行组合搜索时很有用。
PicN("hot") 等价于 PicLib("h|o|t"),生成 id 为 “h”、“o” 和 “t” 的 Text。
3. PicX(Text) 将包含一个单词的 Text 分割成多个包含单独字符的 Text。因此,如果文本包含单词“this”的图像,那么它将返回一个包含 4 个单个字符(“t”、“h”、“i”、“s”)图像的文本,用 | 分隔。在字符之间的间距可能发生变化时(例如,网页每次呈现可能会略有不同),这很有用,因为我们可以将单词分割成单独的字符,最终再执行组合查找,这样字符之间的距离就可以是变化的。
MsgBox, % "将“hot”切片为字符: " FindText().PicX("|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s")
4. PicInfo(Text) 返回有关文本的低层信息。将返回以下数组:
[v, w, h, len1, len0, e1, e0 , mode, color, n, comment, seterr] v --> 0和1形式的文本 w --> 文本宽度 h --> 文本高度 len1 --> 文本中的“1”个数 len0 --> 文本中的“0”个数 e1 --> 以绝对数表示的“1”的允许误差范围(返回len1的%) e0 --> 以绝对数表示的“0”的允许误差范围(返回len0的%) mode --> 0=颜色或未定义,1=灰色,2=GrayDiff,3=ColorPos,4=ColorDiff,5=多色或外部文件 color --> 颜色模式的颜色 n --> MultiColor中的颜色数 comment --> 文本的注释/id seterr --> 是否在文本中设置了误差幅度
示例:
#include <FindText> Text:="|<mycomment>[0.1,0.1]*197$15.1U8A11U8C11k8600s0700Q01U004" info := FindText().PicInfo(Text) MsgBox, % "v: " info[1] "`nw: " info[2] "`nh: " info[3] "`nlen1: " info[4] "`nlen0: " info[5] "`ne1: " info[6] "`ne0: " info[7] "`nmode: " info[8] "`ncolor: " info[9] "`nn: " info[10] "`ncomment: " info[11] "`nseterr: " info[12]
(8) FindText 组合查找
可以通过将 JoinText 参数设置为 1,或指定要查找的单词数组,来完成组合查找。其中 offsetX 和 offsetY 是图像间所允许的最大相对偏移量。如果查找成功,则返回的结果 id 将是用于搜索的 id 的组合(在以下示例中,ok[1].id == "autohot")
Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" Text.="|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" MsgBox, 寻找“auto”和“hot” ok:=FindText(X,Y,,,,,,,Text) ; FindText将分别返回“auto”和“key”的所有位置 for k, v in ok FindText().MouseTip(v.x, v.y) MsgBox, 寻找“auto”后接“hot” ok:=FindText(X,Y,,,,,,,Text,,,1) ; FindText将返回“auto”后面跟着“key”的所有位置,其中“key”在x轴上最多可以与“autom”相距20个像素,在y轴上最多可与“key”相距10个像素 for k, v in ok FindText().MouseTip(v.x, v.y)
如果创建了字符库,则可以使用组合查找来搜索单词。
; 首先让我们将字母“a”和“s”的图像添加到默认图像库 FindText().PicLib("|<a>**50$9.TXz0MzTzXkT7TtvU", 1) FindText().PicLib("|<s>**50$8.DbzXs7kz0wDzTc", 1) FindText(X, Y,,,,, 0.15, 0.15, FindText().PicN("sas"),,,1,5,3) ; FindText().PicN("sas")使用我们的图像库为单词“sas”组装Text。误差幅度设置为15%,因为所有的“a”和“s”字符都有一点不同,如果有15%,就会找到它们的所有实例。偏移X=5和偏移Y=3,因为默认偏移值对于这种情况太大。 FindText().MouseTip(X, Y) FindText(X, Y,,,,, 0.15, 0.15, FindText().PicN("asa"),,,1,5,3) ; 查找单词“asa” FindText().MouseTip(X, Y)
在处理不同字体、浏览器中进行不同渲染或抗锯齿等情况时,同一字符需要有多个图像。此时,我们可以在Text 变量中提供字符集,然后在 JoinText 参数中提供数组形式的搜索词。常规 JoinText 只能使用一种字体。
Text:="|<A>*162$7.472VF4WzkMA" Text.="|<A>*165$8.61UI92NWTYD1U" Text.="|<s>**50$5.Tb3klz" Text.="|<s>**50$5.Tb3klx" Text.="|<a>**50$6.SH3TnnTU" Text.="|<a>*152$5.x4/slz" ; 文本现在包含两种字体“A”、“s”和“A” ok:=FindText(X, Y, , , , , 0.1, 0.1, Text,, 1,["Asa"]) ; FindText将使用提供的字符集查找单词“Asa”的所有实例 for k, v in ok FindText().MouseTip(v.x, v.y)
(9) 光学字符识别 (OCR)
可以使用 FindText().OCR 函数来实现一个基本的光学字符识别器 (OCR)。可以在找到字符集中的所有字符后使用它。
FindText().Ocr( Ok --> 获取 FindText() 返回的结果 ,offsetX:=20, offsetY:=20 --> x 和 y 的最大偏移量。如果超过此 值,则将插入 * 号。默认值为 20 和 20。 ,overlapW:=0 --> 图像的最大重叠,默认为 0 )
返回的是一个关联数组:{text:text, x:X, y:Y, w:W, h:H}
使用 Examples.bmp 的示例:
; 首先让我们将字母“a”和“s”的图像添加到默认图像库 FindText().PicLib("|<a>**50$9.TXz0MzTzXkT7TtvU", 1) FindText().PicLib("|<s>**50$8.DbzXs7kz0wDzTc", 1) ; 使用我们的库查找屏幕上的所有“a”和“s”字符 ok:=FindText(X, Y,,,,, 0.15, 0.15, FindText().PicN("sa")) if (ocr := FindText().OCR(ok, 3, 3)) MsgBox, % "Found " ocr.text ; 应返回 "aaa*sss*asa*sas
更高级的示例是实现记事本搜索功能。在本例中,打开记事本并将字体(在菜单栏 格式 -> 字体...)设置为 Consolas、Regular、11。在记事本中写入一些示例文本,然后运行以下示例并按 F1,这将打开一个搜索对话框。当然在记事本中 Ctrl+F 要好用得多,因为这个 FindText 函数只能查找在记事本窗口中可见的文本,但类似的东西可以用来在游戏中查找文本。
#NoEnv #SingleInstance Force #include <FindText> ; 首先是数字、大写字符和小写字符的一些字符集(取自记事本字体Consolas,Regular,11) numbers :="|<0>*139$10.7Uza6MD1wDnjQz3sD0q6DkS8|<1>*139$9.73sv4M30M30M30M30MzzzU|<2>*139$9.D7wlk60k61UQ71kQ70zzzU|<3>*139$8.TDu70kA6D3s30E43zjm|<4>*139$11.1k3UD0q1g6MMkVX37zzzUM0k1W|<5>*139$9.zryk60k60z7y0k70kCzbsU|<6>*139$10.3sTXUM1U5wzvVw3kBUq6DsS8|<7>*139$10.zzzk30M1UA0k60M30A1U60k8|<8>*139$10.7lza6MBVbCDkT7CMD0y7Tsz8|<9>*139$10.7Vz66kP0w3sRznv081UATVw8" uppercase := "|<A>**50$12.000000003k3k3s7M6M6QCQCAACTyTyM7s7s30000000000U|<B>**50$10.0000003zDysvVy6svzDyszVy7sTzjw000000008|<C>**50$10.0000000TXzSDUC0s30A0s3UC0SAzly000000008|<D>**50$11.0000000DsTwkxUv0y1w3s7kDUP1q7jyTk000000000E|<E>**50$9.000000zzzk60k60zryk60k60zzz00000004|<F>**50$9.000000zzzk60k60zryk60k60k6000000004|<G>**50$11.00000000z3zC6s1k30CDwTs6sBkPknzVy000000000E|<H>**50$10.00000030w3kD0w3kDzzzkD0w3kD0w3000000008|<I>**50$9.000000zzz60k60k60k60k60kzzz00000004|<J>**50$8.00000Dzz1kQ71kQ71kQ7Xjvw0000002|<K>**50$10.0000003VyCsnbCsz3sDUz3iCQsvXi7000000008|<L>**50$9.000000s70s70s70s70s70s70zzz00000004|<M>**50$12.00000000QCQCKOSSSLPrPrPrtbs7s7s7s7s70000000000U|<N>**50$10.0000003Uz3wDsxXrDgyntjayTszXy7000000008|<O>**50$12.000000007sDwSSQ6M7s7s7s7s7M7QCSSDw7s0000000000U|<P>**50$10.0000003zDyszVy3sTXzyzXUC0s3UC0000000008|<Q>**50$12.000000007sDwSSQ6M7s7s7s7s7M7QCSSDw7s1U1n0z0S00U|<R>**50$10.0000003yDwlv3gClnyDknX7AQkv3g7000000008|<S>**50$10.0000000z7ywPUC0S0y0y0w1k7kTzbw000000008|<T>**50$10.0000003zzz30A0k30A0k30A0k30A0k000000008|<U>**50$10.00000030w3kD0w3kD0w3kD0y7sxzXw000000008|<V>**50$12.00000000s3s7M6Q6QCACCACQ6Q6M7s3s3k3k0000000000U|<W>**50$11.k7UD0y1w3tbnjjPSqxhDSSwxsu|<X>**50$11.sDktnVr3w3k7UD0z1y7CCCsRUS|<Y>**50$11.kDUTVnX7C7MDkD0C0M0k1U3062|<Z>**50$10.0000003zzz0M3UQ1UC0k60s30M3zzz000000008" lowercase := "|<a>**50$10.000000003wTtVk7Dxzy7sTXrzDQ0000008|<b>**50$10.03UC0s3UCwzvty7sDUy3sTXzyTU0000008|<c>**50$10.000000001yDxsr0M3UC0M1knz7s0000008|<d>**50$10.001k70Q1lzTxly7sT1y7sTbrzDQ0000008|<e>**50$10.000000001wTtly3zzzy0s1k7zDw0000008|<f>**50$11.003wDss1k3UzxzsQ0s1k3U70C0Q0s00000002|<g>**50$11.0000000007zTytnVX77yDss1k3zXzi3wCzwzW|<h>**50$10.03UC0s3UCwzvtz7sTVy7sTVy7sQ0000008|<i>**50$9.71s70007sz0s70s70s70szzz000000U|<j>**50$9.1kD1k003yTk60k60k60k60k60qCzXsU|<k>**50$9.060k60k67lqQr7ky6sr6Qlq7000000U|<l>**50$9.07sz0s70s70s70s70s70szzz000000U|<m>**50$11.000000000TizxrTCyNwntbnDaTAyNk0000002|<n>**50$10.00000000Cwzvtz7sTVy7sTVy7sQ0000008|<o>**50$10.000000003wTvny7kD0w3sTnryDk0000008|<p>**50$10.00000000Cwzvty7sDUy3sTXzyzXUC0s3U8|<q>**50$10.000000001zTxly7sT1y7sTbrzDQ1k70Q1s|<r>**50$9.00000006yzzbsS0k60k60k60000000U|<s>**50$9.00000003wzr6s7UTUS0y6zrw000000U|<t>**50$11.0000A0s1kTzzyC0Q0s1k3U7070DsDk0000002|<u>**50$10.00000000C7sTVy7sTVy7sRrrzDQ0000008|<v>**50$10.00000000A3sTVq6QsnXADkO1s7U0000008|<w>**50$12.0000000000s3s7s7NbNqPqPqOKSSSSCS00000000U|<x>**50$10.00000000C7QRnXw7US1wDlnb7sQ0000008|<y>**50$12.0000000000M7QCQCAACQ6M7M7s3k3k1U3U70z0w0U|<z>**50$10.000000007zTs3UQ1UA1UC1k7zzw0000008" characterset := lowercase . uppercase . numbers ; 将我们新创建的字符集添加到PicLib库 FindText().PicLib(characterset, 1) return F1:: InputBox, searchPhrase, 搜索记事本, % "在记事本上搜索一些文本。要使搜索区分大小写,请将搜索词放在引号中。" caseSensitive := (SubStr(searchPhrase,1,1) == """") && (SubStr(searchPhrase,0) == """") if caseSensitive searchPhrase := SubStr(searchPhrase,2,-1) ; 对于区分大小写的搜索,请删除双引号 else StringLower, searchPhrase, searchPhrase ; 对于不区分大小写的搜索,请将搜索短语变成小写 if (ok:=FindText(X, Y,,,,, 0, 0, caseSensitive ? FindText().PicN(searchPhrase) : RegexReplace(characterset, "(?<=<)\p{L}(?=>)", "$L0"),1,1, caseSensitive ? 1 : [searchPhrase])) ; 如果进行区分大小写的搜索,请使用PicN将搜索短语中每个字符的图像粘在一起,然后使用FindAll=1查找结果图像。如果进行不区分大小写的搜索,请将字符集中的所有大写字符替换为小写字符(这意味着FindText将在搜索中同时使用大写和小写图像),然后查找小写搜索短语。 { FindText().MouseTip(X, Y) ; FindText().Click(X, Y, "L") } return
(10) BindWindow - 搜索遮挡窗口文本
BindWindow 允许 FindText 在被其他窗口遮挡的窗口中搜索文本。
FindText().BindWindow( bind_id -> 获取目标窗口的 ahk_id(这可以通过 WinExist() 获得)。 如果设置为 0,则禁用 BindWindow,采用正常方式搜索屏幕。 , bind_mode -> 指定绑定的方法。有些窗口支持某些方法,有些窗口需要 其他的方法。奇数 bind_mode 会修改一个透明窗口以在其中进行搜索。通 常 bind_mode 为 0 或 4 时起作用,默认为 0。 ,get_id -> 如果设置为 1,则返回当前绑定窗口的 id,默认为 0。 ,get_mode -> 如果设置为 1,则返回当前使用的绑定模式,默认为 0。 )
SetTitleMatchMode, 2 FindText().BindWindow(WinExist("Paint ahk_class MSPaintApp")) ; 将FindText绑定到绘制 Text:="|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" FindText(X, Y, 72-150000, 228-150000, 72+150000, 228+150000, 0, 0, Text) ; 绘制可能会被另一个窗口遮挡,但FindText仍能找到Text FindText().MouseTip(X, Y) FindText().BindWindow(0) ; 从FindText取消绑定Paint
注意!BindWindow 将为运行脚本中的所有 FindText 函数进行全局设置。如果使用多个线程,则新线程可以覆盖旧线程的绑定窗口(例如,一个热键绑定一个窗口并循环 FindText,然后被另一个绑定另一个窗口的热键中断)。可以通过使用 FindTextClass 来避免这种情况,具体将在下面讨论。
(11) FindTextClass 查找文本类
FindText 的每个函数都包含在一个名为 FindTextClass 的类中。FindText() 返回 FindTextClass 的全局共享实例,因此 FindTextClass 的每个函数都在同一个数据集上运行。例如,BindWindow 为每个 FindText 调用更改其绑定窗口,Screenshot=0 将使用任何 FindText 调用最后创建的屏幕截图,等等。FindText(arguments) 与 FindText().FindText(arguments) 是相同的。
对于此示例,在 Paint 中打开“Examples.png”,然后通过在其上方移动另一个窗口来隐藏图像。按 F1,鼠标提示找到的图像的位置。按F2 后,找不到图像了。
#NoEnv #SingleInstance Force #include <FindText> Esc::ExitApp F1:: FindText().BindWindow(WinExist("Examples.png - Paint")) Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" while (ok:=FindText(X, Y,,,,, 0, 0, Text)) { FindText().MouseTip(X, Y) Sleep, 1000 } MsgBox, 找不到Paint了! return F2:: FindText().BindWindow(0) ; 或者绑定另一个窗口? return
这可以通过使用 FindTextClass 的新实例来解决:
F1:: ft := new FindTextClass ft.BindWindow(WinExist("Examples.png - Paint")) Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" while (ok:=ft.FindText(X, Y,,,,, 0, 0, Text)) { ft.MouseTip(X, Y) Sleep, 1000 } MsgBox, 找不到Paint了! return
(12) 截图功能:ScreenShot、GetTextFromScreen、SavePic、ShowPic、ShowScreenShot
1. FindText().ScreenShot(x1:=0, y1:=0, x2:=0, y2:=0)
在点 x1,y1 和 x2,y2 之间获取 FindText 内部屏幕截图,以便在以后的 FindText 调用中使用。
2. Text := FindText().GetTextFromScreen(x1:=0, y1:=0, x2:=0, y2:=0, Threshold="", ScreenShot:=1, outX, outY)
使用指定的阈值将 x1,y1 和 x2,y2 之间的截图转换为 Text。Threshold 可以是灰度阈值模式的“*”或灰度差值模式的“**”,后跟阈值。ScreenShot = 1 将拍摄一个新的屏幕截图,取值为 0 表示使用最后一个内部屏幕截图(例如由 ScreenShot 函数生成的截图)。文本将自动从顶部和底部裁剪。变量 outX 和 outY 将设置为包含屏幕上抓取文本的中点。
3. FindText().SavePic(FileName, x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1)
将 x1,y1 和 x2,y2 两点之间的截屏区域保存到一个文件中。
4. FindText().ShowPic(FileName:="", show:=1, outX, outY, outW, outH)
在屏幕左上角显示一个图像文件内容。outX 和 outY 将设置为显示图像的 X 和 Y 坐标(在多屏幕设置中,此坐标可能不是 0,0),outW 和 outH 设置为图像的宽度和高度。在不指定 FileName 的情况下调用 ShowPic() 将从屏幕中删除图像。
5. FindText().ShowScreenShot(x1:=0, y1:=0, x2:=0, y2:=0, ScreenShot:=1)
与 ShowPic 函数一样,显示点 x1,y1 和 x2,y2 之间的区域。如果 ScreenShot 为 1,则将拍摄新的屏幕截图,否则使用最后一次的内部屏幕截图。
示例:
#include <FindText> FindText().Screenshot(100,100,500,500) ; 在坐标100, 100和500, 500之间进行新的屏幕截图 FindText().ShowScreenShot(100, 100,500, 500, 0) ; 在屏幕上显示拍摄的屏幕截图。由于我们指定0作为最后一个参数,该函数将使用screenshot函数之前拍摄的屏幕截图。 Sleep, 3000 FindText().ShowScreenShot() ; 3秒后隐藏屏幕截图 FindText().SavePic(A_ScriptDir "\TestScreenShot.png", 100, 100, 400, 400, 0) ; 将截取的屏幕截图的一部分保存到脚本目录中的文件中。
(13) 杂项:Sort、Sort2、Sort3、WaitChange
1. FindText().Sort(ok, dy:=10)
接受一个 FindText 结果数组(ok),返回一个从左到右 -> 从上到下排序的数组。比较点位于图像的中间(不是左上角!),通过改变 dy 值可以忽略 y 位置的细微差异。
2. FindText().Sort2(ok, px, py)
接受一个 FindText 结果数组(ok)和一个坐标(px, py),并使用 (x-px)^2 + (y-py)^2 公式计算图像与坐标的距离,进而对数组进行排序。
3. FindText().Sort3(ok, dir:=1)
接受一个 FindText 结果数组(ok),按方向排序。Dir 与 FindText dir 参数取相同的值(9 除外)。
4. FindText().WaitChange(WaitTime:=-1, x1:=0, y1:=0, x2:=0, y2:=0)
等待 “WaitTime” 秒,看坐标 x1,y1 和 x2,y2 之间的屏幕区域是否变化。将 “WaitTime” 指定为 -1 将无限期等待。
(14) FindText 速度提升技巧
1. 使用尽可能小的搜索范围。可以通过多种方式实现,最简单的方法是使用 WinGetPos 将搜索限制在单个窗口中,以获取窗口位置和大小。
WinGetPos, pX, pY, pW, pH, ahk_class MSPaintApp ; 获取“Paint”应用程序的位置和大小。 ok := FindText(X, Y, pX, pY, pX+pW, pY+pH,,, Text) ; 将搜索范围仅设置为“绘制”窗口
有时搜索到的图像只会出现在特定区域,因此可以进一步调整搜索范围。在 Paint 窗口中,如果我们对菜单栏和工具栏不感兴趣,那么我们可以从顶部裁剪一部分:
WinGetPos, pX, pY, pW, pH, ahk_class MSPaintApp ; 获取“Paint”应用程序的位置和大小。 ok := FindText(X, Y, pX, pY+150, pX+pW, pY+pH,,, Text) ; 将搜索范围设置为仅“绘制”窗口,并从顶部裁剪150像素以忽略菜单栏和工具栏
2. 使用尽可能小的图像。可以通过使用 L3/R3/L/R/U/B/自动裁剪按钮,来裁剪抓取的图像。
3. 使用尽可能小的误差范围。例如,将 err1 和 err0 从 0 提高到 0.3 可能会导致搜索速度明显变慢(可能慢 5-10 倍)。
4. 如果要查找完全匹配,请为 err1、err0 或两者指定一个非常小的非零值。FindText 的默认动作是:如果 err1 和 err0 都设置为 0,那么如果搜索失败,将自动将 err1 和 err0 都设置为 0.05 并重新尝试搜索。当执行许多 FindText 调用来查找不同的图像时,这种额外的搜索会随着时间的推移而增加。但这仅在 err1 和 err0 恰好为 0 时发生,这意味着如果您将诸如 0.000001(很接近 0 但不等于 0)用于 err1、err0 或两者同时设置(只需一个非零),那么只会执行一次搜索(有效误差范围为 0.000001≈0)。
FindText(X, Y,,,,,,, Text) ; 如果Text在屏幕上不可见,则搜索会发生两次:第一次将err1和err0设置为0,然后再次设置为0.05(5%的误差范围) FindText(X, Y,,,,,0.000001,, Text) ; 如果文本在屏幕上不可见,则只进行一次搜索,以寻找完全匹配的文本(0.000001≈0) FindText(X, Y,,,,,0.05,0.05, Text) ; 如果文本在屏幕上不可见,则只进行一次搜索,但会留下5%的小误差
5. 如果要搜索多张图片,要么将 Text 拼成一个然后只调用一次 FindText,要么将 Screenshot 参数设置为 0 以进行后续搜索。这避免了 FindText 多次进行屏幕截图,这需要耗费大量时间。
使用组合查找方法的示例:
Text:="|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8" Text.="|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s" if (ok := FindText(X, Y,,,,,,, Text)) { if (ok[1].id == "auto") { ; 找到“auto”图像后执行操作 } else if (ok[1].id == "hot") { ; 找到“hot”图像后再做一些事情 } }
重用第一个屏幕截图的示例:
FindText().PicLib("|<auto>*159$40.0000k000003000000A00DVUnw7lr6371nUAMAA630FUkkkAT63330rgMAAA1kFUkkkD363330wAAAA62vkvkkQtt1v1kS8",1) FindText().PicLib("|<hot>*152$29.U00010000200014000280004Hk7kzxktktVVUkX161V43A3286M24EAkA8UNUMF0lUUW1Xb1g31s1s",1) if (ok := FindText(X, Y,,,,,,, FindText().PicLib("auto"))) { ; 找到“auto”图像后执行操作 } if (ok := FindText(X, Y,,,,,,, FindText().PicLib("hot"), 0)) { ; 使用之前拍摄的搜索“auto”的屏幕截图调用FindText ; 找到“hot”图像后再做一些事情 }
6. 使用需要最少像素比较次数的捕捉模式。通常灰度阈值模式是最快的选择;灰度差值、颜色位置 和 相似度设置为 100% 的颜色相似模式也非常快。最慢的是颜色相似模式(颜色范围越大或相似度越低 -> 搜索越慢)和多色查找(如果使用的是图像文件)。
这就是现在的全部内容,感谢您的阅读!
原文的更新历史: 09.05.22: 1) Added explanations for ScreenShot, GetTextFromScreen, SavePic, ShowPic, ShowScreenShot, WaitChange, PicInfo. 2) Specified that MultiColor mode can also use filenames. 3) Added an advanced OCR example. 17.05.22: 1) Added section "FindText speed improvement tips" 2) Added more examples under the main FindText function explanation 3) Added ColorDiff mode explanation 4) Corrected typos and made some wordings better.
FindText 后台点击屏幕坐标
可以将FindText().Click(x, y) 换成下面的
; 后台点击屏幕坐标 Click2(x, y, WhichButton:="", ClickCount:=1, Delay:=20) { if !(hwnd:=DllCall("WindowFromPoint", "Int64", x&0xFFFFFFFF|y<<32)) return WinGetPos, winx, winy,,, ahk_id %hwnd% WhichButton:=StrReplace(WhichButton, "Button") Loop % ClickCount { ControlClick, % "x" (x-winx) " y" (y-winy), ahk_id %hwnd%,, %WhichButton%,, D Pos Sleep % Delay ControlClick, % "x" (x-winx) " y" (y-winy), ahk_id %hwnd%,, %WhichButton%,, U Pos Sleep % Delay } }
评论(0)