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

ice · June 18, 2019 · Last by chend replied at July 04, 2019 · 1658 hits

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,修改类参数,偏移值DEVIATION0,用以获取精准的截图区域
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
共收到 9 条回复 时间 点赞

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

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

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

ice #4 · June 19, 2019 作者
saint228 回复

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

ice #5 · June 19, 2019 作者
steven 回复

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

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

ice 回复

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

ice #7 · June 20, 2019 作者
saint228 回复

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

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

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

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up