Airtest 在 airtest 中使用 ocr 反向识别文本内容进行断言

匿名 · 2019年06月18日 · 2639 次阅读

airtest 是网易开发的一款基于图象识别的 ui 自动化框架,其对元素操作的流程是先对元素进行截图,再和客户端当前界面截图进行对比,找出位置,执行点击操作。

这样的操作免除了传统的查找控件的繁杂,但是对元素的断言却不够精细,尤其在不仅仅判断元素是否存在,而且还要对文本的内容进行检查时,可以说无能为力了。

想要解决这个问题,可以使用回归传统的元素查找方式(airtest 内置了各端通过元素查找方式的 api),查找到元素,再判断他的文本属性,得到内容;但这样的方式第一需要在元素的映射方式上增加传统的例如 xpath 的关系,第二很多时候由于不规范开发等原因,元素的定位属性往往不容易确定,花费时间查找其实已经丢失了图像识别控件的便利性。

在实际的操作中(我的项目是 pc 端 + 安卓端双端互动的场景),我发现可以利用 airtest 本身的 api,外加 ocr 的 python 库,做到对元素内容的识别,从而解决这个问题。

大概的思路是,先用 airtest 本身的 api,将待识别内容截图扣下来,然后利用 ocr 的库进行对其内容识别。

理论上,如果你的设备分辨率不会变更,那么其实不需要用到 airtest 的 api,直接用固定的位置,通过 opencv 等图像处理的库进行抠图保存即可,但由于生产设备的分辨率不能保证,因此,需要一个相对的位置,对这个位置,airtest 里有直接可用的方法,这个方法也是其本身对分辨率兼容的办法。

airtest 通过你截图时记录的坐标,设备分辨率,来生成一个 recordpos,这个 pos 其实就是一个用来计算当分辨率不同时他的坐标偏移量。

具体怎么通过 recordpos 进行计算坐标,这里就不赘述了,主要说一下通过 recordpos 进行元素查找的方法,这个方法是 get_predict_area,有四个参数,分别是 record_pos(截取控件图片时的偏移量)、image_wh(空间的宽高)、image_resolution(截取图片时记录的设备分辨率)、screen_resolution(查找控件时所在设备的实际分辨率)。

该方法会返回一个四角坐标,我们把这个四角坐标用内置的图片处理方法,在设备及图上进行截图保存,就可以获取到待识别控件的图片啦,然后再用 ocr 库对这个图片进行识别,就可以得到控件的文本内容了。

示例代码如下(只适用于本人的硬件设备,用作参考):

dev = device()
stu_answer_num = r'./valid_pic/stu_answer_num.png'  # 答题区域的截图路径
interact_pic_path = r'./valid_pic/snap_interact.png'  # 互动界面的截图路径
interact_image = dev.snapshot(interact_pic_path)  # 把互动界面截图保存

from PIL import Image
import pytesseract
from airtest import aircv
from airtest.core.cv import Predictor

screen_resolution = aircv.get_resolution(interact_image)  # 获取互动界面截图的实际分辨率
# 动态创建类继承自Predictor,修改类参数,偏移值DEVIATION为0,用以获取精准的截图区域
predictor = type('Pos', (Predictor,), {'DEVIATION': 0})
xmin, ymin, xmax, ymax = predictor.get_predict_area(record_pos=(0.404, -0.213), image_wh=(265, 45),
                                                    image_resolution=(1919, 1040),
                                                    screen_resolution=screen_resolution)  # 获取答题区域的截图坐标
predict_area = aircv.crop_image(interact_image, (xmin, ymin, xmax, ymax))
aircv.imwrite(stu_answer_num, predict_area)  # 将待识别区域进行截图保存
answer_str = pytesseract.image_to_string(Image.open(stu_answer_num), 'chi_sim')  # 识别出的文字类似’全 班 共 参 与 : 1/1‘
print(answer_str)
if answer_str.find('参 与'):
    answer_str = answer_str.split(' ')[-1]  # 取1/1
    answer_num = int(answer_str.split('/')[0])  # 取答题人数
    return answer_num
return
共收到 11 条回复 时间 点赞

ocr 使用的是 tesseract,需要提前安装并配置好环境变量

先用图像识别找出控件,再用 ocr 识别出控件的文字,校验文字是否正确? 那图像识别的时候能匹配到还不足以证明文案显示正确? OCR 也有误差啊

OCR 很不可靠。如果你们是用 unity、cocos 等通用引擎,建议还是用 airtest 集成的 poco 来抓控件识别。花十几分钟打个 SDK 进去重新编译即可。

匿名 #4 · 2019年06月19日
saint228 回复

针对特定系统的文本是可以制作训练集的,这个也是看场景吧,我们的文本都是标准的电脑字体,只要分辨率够,几乎 100% 识别

匿名 #5 · 2019年06月19日
steven 回复

不是找出控件,是先算出该文案的相对位置,再把这个位置的图扣下来,再用 ocr 进行识别;

此外,airtest 能匹配到也并不能代表文案是正确的,尤其是文案相似度很高的时候。

不知道效率如何?要先截图、然后存本地,再调用第三方的库解析图片。我估计一次完整操作至少得 1、2 秒钟吧。

匿名 #7 · 2019年06月20日
saint228 回复

1s 以内吧,具体我没算过,我循环 print 的,基本都是 1s 以内可以 print 出文本

tesseract 配置好环境变量和最好是有字体库,一般是提前截图和预处理(可以缩小提高精度).Ocr 是做美术字识别
另外 airtest cv2 没有完全 open.

如果中文的化,可以直接用百度云的 API, 免费一天 1000 次,用来解决问题足够了.
另外: 感觉举得例子有点不太合适,文字也可以被当作图片来做识别的, 可能是一些逻辑判断分支的情况下, 才会 OCR 识别出文字然后做逻辑处理.

僅樓主可見
匿名 #11 · 2020年02月07日
回复

为啥你会问我这个?

需要 登录 後方可回應,如果你還沒有帳號按這裡 注册