注:我们的 Airtest 官方公众号(AirtestProject)会持续更新大家对于 Airtest 感兴趣的问题,欢迎有需要的同学关注并查看我们更多的内容。

原文地址:https://airtest.doc.io.netease.com/tutorial/9_Improved_compatibility/

提高截图脚本兼容性

1.截图脚本常见的问题情景

在脚本测试的过程中,有时候我们会遇到下面这些情况:

①之前写好的截图脚本在更换一台不同分辨率的手机/更换一个环境之后,就经常遇到执行失败的报错:


报错的文字版本是:

airtest.core.error.TargetNotFoundError: 'Picture Template(E:\\test\\pycli\\untitled7.air\\tpl1570692325989.png) not found in screen'

这是因为图像识别具有一定的误差,在不同分辨率的设备上,或是画面发生了一定变化的情况下,可能会造成图像识别效果不如预期的情况。我们可以尝试各种方法修改截图,来获得更高的截图识别成功率。

②运行后查看报告,发现识别出来的位置是一个错误的位置,但是 airtest 当做是正确的。这种情况下,就需要通过调整截图、调整阈值之类的手段来修改脚本。

③运行后查看报告,报告里能看到识别到了正确的位置,也点击成功了,但是实际上没有成功点到。

这是因为在脚本编写过程中,如果有连续点击操作,屏幕内容可能会不断变化,有时候会导致脚本明明运行到了点击操作却发现没有生效的情况。这是因为屏幕内容切换速度过快,界面还未稳定的同时 airtest 就进行了元素识别和操作,导致没有成功点击到对应元素。

因此我们通常建议,在一些操作步骤结束后,适当等待一个合适的时间再进行下一步操作,例如:

from airtest.core.api import *
start_app("test_package")
sleep(5)
touch([500, 500])
sleep(1)
touch([600, 0])

2.提升截图脚本兼容性的方法

2.1 截图技巧

①截图时尽量保证截取的图像辨识度高、独立清晰 ,例如截取一个按钮图像时,尽量不要带上太多的嘈杂背景图案,避免在背景变化后难以成功识别的问题。

这样干净的截图:
会比这样的截图好:

②图像识别使用的算法更适合用来识别按钮类(带边框)、图标类的图像 ,仅仅单独截取几个文字的识别成功率很低,请尽量调整图片截取内容来达到较好的识别效果,避免截取识别效果较差的内容。

若有大量重复的、非常相似的图标堆叠在一起时,有可能识别效果不佳,在我们眼中也许每一个图标上面的文字是不一样的,然而在 Airtest 的眼中它们实在是太相似了。我们可以尝试修改截图,借助一些其他的背景样式,修改成辨识度更高的图片。
例如对于这样子的界面:


我需要点击中间第二个【安装】按钮。如果直接截图
可能根本点击不到,或者点击到错误的按钮。

但是如果我们换一种方式,截取拥有更多特征的图片:


,返回的结果则会是正确的。因为 Airtest 默认点击的是我们截图的中间位置,所以这样截图正好可以实现点击第二个【安装】按钮的效果。下文我们还可以通过设置点击位置 traget_pos,来实现第一个或第三个【安装】按钮的点击。

④尽管我们提供了便捷的自动录制功能,能够直接将当前所有操作一步一步转换成代码,但是这种情况下自动截取的图片往往不太理想,需要手工再对截图进行调整。下图是使用自动录制功能截出来的图片,可以看出截图的特征并不那么明显。

2.2 合理调整阙值

在每行图像识别脚本运行的时候,包含三个步骤:① 图像识别的初步识别结果;② 计算结果可信度;③ 通过脚本中的阈值筛选结果。


脚本中的阈值在这里起到结果筛选的作用,阈值的高低将直接影响到返回的识别结果:

阈值过高:可能导致把低可信度的初始结果全部过滤掉,最终没有有效的图像识别结果。

阈值过低:可能导致返回的是错误结果(没有正确识别结果的情况,因为阈值过低使得错误结果得以通过筛选)。

我们在提升图像脚本兼容性的时候,最重要的一个部分就是设置合理的阈值。Airtest 框架中的默认识别阈值为 0.7,我们可以进行适当调整。

使用 “图像编辑器” 调整单行脚本阈值

我们一般使用 “图片编辑器” 修改阈值。在脚本框中双击图片打开 “图片编辑器”,我们可以实时调节右侧的 threshold 阈值数值,并点击 Snapshot + Recognition 按钮来实时验证识别结果。识别结果的可信度会直接呈现在下方状态栏上,可信度大于阈值时才会返回识别结果:


注意: 建议阈值设定在 [0.6, 0.9] 之间,避免阈值过低混入错误结果、或者阈值过高导致经常找不到结果。

设置脚本的全局阈值

如果我们想直接为整个测试脚本的图像脚本设置阈值,则可以在脚本开头时进行全局阈值的设置:

# 全局阈值的范围为[0, 1]
from airtest.core.setting import Settings as ST
ST.THRESHOLD_STRICT = 0.7  # assert_exists语句的默认阈值,一般比THRESHOLD更高一些
ST.THRESHOLD = 0.7  # 其他语句的默认阈值

2.3 利用灰度图识别

在识别图像时,Airtest 会先将图像转为灰度图再进行识别。因此假如有两个按钮,形状内容相同,只有颜色不同的情况下,Airtest 将认为它们都是相同内容。如下图,如果仅截图第二个红色的【删除】按钮,Airtest 会把另外俩个灰黑色的【删除】按钮认为是相同的。


通过勾选 rgb 选项(双击图片打开图片管理器勾选),或在代码中加入 rgb=True,我们可以强制指定使用彩色图像进行识别。这样就能比较好地识别出那个红色的【删除】按钮了。

2.4 设置点击位置 traget_pos 来进行点击

当识别出一张图像后,Airtest 将会默认去点击图像的正中心位置,有时我们希望它识别出图片后点击其他位置,就可以通过修改 target_pos 属性来实现。

例如:



在上图中,我们希望点击中间选项的 “升级” 按钮,不希望点到别的选项去,而只截出升级按钮不能满足我们的需求。

此时我们可以考虑将截图范围扩大到红色虚线框选的区域,截图后将这张方形图片视为一个九宫格,方框上的每一个暗色红点都代表一个数字,将希望被点击的位置设置为 target_pos 的值即可。在这个例子中,我们可以让截图区域的底部正好放在 “升级” 按钮上,然后设置 target_pos=8 即可正好点击到该按钮。

target_pos 取值范围是 1~9,[1, 9],且必须为整数,默认值是 5(图像正中心)。同理,上文的安装按钮的例子,也可以通过设置 target_pos 来识别第一个和第三个按钮:

2.5 自定义语句提高图像脚本兼容性

对于设备长宽比不同、设备分辨率不同、多种字体的情况,我们可以通过语法来提高兼容性。这种方式需要连接上脚本兼容性有问题的设备,把对应截图纳入搜索列表。代码脚本如下:

picList = [pic1,pic2,pic3]  # 截图的图片对象列表
for pic in picList:
     pos = exists(pic)
     if pos:
         touch(pos)
         break  # 只要找到图片列表中的任何一张图片,就执行touch

注意:如果for循环中没有break语句,会导致次逻辑运行时将所有的图片都找一遍 (找到后执行touch),而非找到合适结果立即返回。

3.指定游戏的分辨率适配规则

在使用不同分辨率的设备进行图像识别时,可能会导致识别成功率不佳,因此 Airtest 提供了默认的分辨率适配规则(使用的是Cocos 引擎的默认缩放规则),代码在这里。

想要提高 2d 游戏的识别精度,最好的办法就是明确指定你的游戏的分辨率适配规则,例如,直接在.air 脚本文件的开头这样写:

from airtest.core.api import *

def custom_resize_method(w, h, sch_resolution, src_resolution):
    return int(w), int(h)

# 替换默认的RESIZE_METHOD
ST.RESIZE_METHOD = custom_resize_method

上面的代码指定了一个自定义的缩放规则:直接 return 原来的值,不管屏幕分辨率,所有 UI 都不进行缩放(有的游戏就是这种策略)。

这里的RESIZE_METHOD,即我们定义的custom_resize_method使用的输入参数为:

输出为:

若要自定义你的RESIZE_METHOD,只需要知道你测试的游戏的缩放规则,然后在custom_resize_method中用代码实现即可。这样做,能够大大提升不同分辨率设备下的图像识别成功率。

4.拓展阅读

Airtest 采用的多种图像识别算法的效果比较,可以参考这里

最后,如果大家对 Airtest 有疑问、BUG、建议,请到https://github.com/AirtestProject/AirtestIDE/issues 发布 issue,我们会有专人解答。同时,我们还提供了官方 QQ 群给大家沟通交流,目前 1 群已满,欢迎大家加入 2 群:


↙↙↙阅读原文可查看相关链接,并与作者交流