一个简单的APP

2024年02月27日

过完年又开始忙了,新年新气象,各方都“蠢蠢欲动”,想搞点大新闻。

一会是要帮客户把厂商A的数据接入B系统,被厂商说不懂研发。一会是X项目经理说Y公司帮甲方做的项目被基层喷的很惨,甲方要我们来救火,这是不是有一种钦定的感觉?🤣

好在我已经历生离死别,看淡了很多,没以前那么焦虑。正好最近高达seed剧场版,所有用seed系做个比喻,有种seed-d里看海基神的感觉。😂

正好被这几座大山压迫的时候,接到通知又要某考试了。好嘛,一季度考一次,每次考试都要背一半和本专业毫无关系的题,甚至有一些我连题目都看不懂,这次题库增还加到了800多道。我记得有道题是说本考试应该多长时间考一次,正确答案是“每年”…层层加码了属于是。

这么搞大家都怨声载道的,本基神也打算削个人棍发泄一下。

不过,基神削人棍得有自由高达,我什么也没有,也不是东方不败能空手拆机。好在考试是在手机上进行,于是花了几天时间撸了一个Android程序,勉强可以算是波士机器人吧。😄

基本思路是打开软件->导入题库->启动浮窗->打开考试软件->点击浮窗上的按钮->截屏->设置识别区域->OCR->去题库里找题->标记答案。虽然耗时不多,但是过程还是遇到了一些坑。

OCR的选择

以前项目用过一个叫Tesserocr的库,效果不好被客户吐槽过。本以为这几年机器学习、人工智能飞速发展,OCR不是小菜一碟?找来找去发现中文OCR可选项竟然不多,开箱即用的更少,那些个百度、华为、TX的OCR SDK都是要把图片传到服务端分析,免费配额也不多。

免费而且离线的主要试了两个,百度Paddle和谷歌的MLKit-OCR。

MLKit

先尝试了一下MLKit,它是谷歌官方出品的机器学习套件,以前用过来做二维码识别,比zxing的效果好太多了。

OCR库叫做text-recognition,只需要几行代码就可以跑起来,支持离线,也不需要Google Play。

试用了一下,效果不错,识别结果有很好的层次结构,文字块->行->元素,层次清晰。

再用了用,发现即使是截屏这种很清晰明确的文字都有几率出错。比如“措施”识别成“搭施”,逗号识别成句号,这其实都还好。比较离谱的是会把“工作”识别成“エ作”,我看了半天没看出问题来,后来发现似乎是日语片假名エ(e)。

Paddle

因为MLKit OCR的这些小问题,我又换了百度的Paddle,搜了一下说这是最好的中文OCR。它并不是一个开箱即用的SDK,DEMO都需要配置NDK才能运行,我只想找一个轮子,可它似乎只是一个轮毂。后来找到一个大佬封装后的库叫paddleocr4android,按照示例试了试居然跑起来了。

按照大佬的文档下载了ch_PP-OCRv3模型测试了一下。

Paddle的识别率我感觉和MLKit差不多,也有些符号上的小错误和错别字。有时候还会多一个字,比如“依据”会被识别成“依衣据”。但我没有碰到中文字符被被识别成莫名其妙的其它字符。

Paddle识别出来的层次结构就是以行为单位,并不会把相邻的段落聚合成一个文字块,不过这对我影响不大。

后来也碰到个比较离谱的情况,如“xxxx由()组织”,由于两个括号的字符不太一样,会导致后半括号被识别成一个斜向上的文字,这个短语被识别成了“xxxx由(”和“)组织”两个block。OCR本身的排序算法认为后面的括号左上角更高,所以它应该属于上一行,这就导致又出现了一个离谱的结果,“xxxx由()组织”被识别成了“)组织xxxx由(”。

解决方法倒也比较明确,自己写一个排序算法,设置一个阈值,y坐标比较时大于该阈值的文字块才被算作上一行,否则被算作本行。

匹配问题

试了这里两个SDK,文字识别已经没办法再提升了,下面开始匹配题目。

本来想得很简单,迭代所有题目,并且用“相等”或者“包含”,找到满足条件的题目,显示答案即可。

拿来做了个模拟测试,做了几题就不行了😑,无论是OCR还是题库的瑕疵远比我想象中要多,单纯的“相等”或者“包含”很多时候难以匹配,不得不想点别的办法。

预处理

标点符号一般很容易识别错,英文和中文的括号鬼才识别得出来,所以无论是导入时还是检索前,把各种标点符号全部去掉就完了。

一些算法

以前做人脸识别得时候知道向量有余弦相似度,其实文字处理也可以用,另外还有很多专为文字准备的算法,我选了Levenshtein,因为Apache Commons Text里有这个算法😏。

这个算法的主要问题在于必须自己确定阈值,而阈值往往又和文字的长度相关。文字比较多的时候,识别算法更加容易出现瑕疵,导致需要较大的阈值;文字简短时,较大的阈值又会带来过多的匹配结果,得适当调小,但又不能太小。

于是给chatgpt提供了几个文字长度和阈值的对应关系,让它帮我拟合了一个函数。其实就是个简单的log函数,正好满足我的需求。

组装完毕

把这些问题解决完毕之后,APP就基本搞定了。做了个模拟测试轻松通过,再稍作改进就满分了。

最后决定给APP加个图标,正好小万万天天看海底小纵队,那就用章鱼图标吧🤣,自用程序也不用考虑太多。

好了,暂时就这样吧,看我自…哦不…波士机器人的“DX·老大拳”!!!