最开始是因为复习高数的时候想要做笔记,就需要写各种各样的公式,这里就有很好用的工具Mathpix Snip ,专业,高效,优雅。
然后它突然告诉我次数不够了。
emm,突然不免费了,而且价格也有点不近人情。
后来过了几天我拿C#用腾讯的接口实现了个备用的,再后来就是切换到ubuntu,电脑文件在装系统的时候丢失了。
那就再用shell写个吧,我这么想到。
这其实算是个回忆归档的记录吧,当初完成的时候碍于精力就搁置了,然后有时间了就拿出来拾掇拾掇。
最开始是打算写出个自用的,可是种种原因最后变成了对比体验。
整篇文章以记录为主,许多查得到细节就不一一展开了
分析
让我自己去实现一个OCR程序肯定是不行的,得从头学起,然后训练,最后精度肯定不得行。占用了相当的时间——我还得考研呐。
所以去找第三方接口用是更实际点的思路(实际上在之前以我的知识储备一直不知道有这么条路走),然后我大概找了这么几个方案。
腾讯云 ,百度智能云 ,讯飞开放平台 ,以及业界领先Mathpix Snip ——让我又爱又恨。
开发
腾讯云
腾讯云的帮助文档写的不错,还特地开发了保姆级别的交互教程API Explorer ,填进去参数,选择一个主流的开发语言,自动生成代码。
不过我最中意的还是它的命令行工具:tccli ,既然都换成ubuntu了,不好好练练shell怎么能行。况且,借助shell强大的生态,和其他程序形成联动的话,就能省下很多精力。
先安装
通过tccli的帮助文档确定了tccli的使用方式:tccli [options] <command> <subcommand> [<subcommand> ...] [parameters]
,先选择想要调用的应用类型,然后给出参数。
一步步确定后就知道需要调用的是ocr中的FormulaOCR应用,在配置完成后只需要一个重要参数--ImageBase64
,然后系统自带的就有 base64 工具,直接调用就行。
返回的数据是一串json,不过它也自带了解析器,通过--filter
参数调整就行,最后的话就是通过这么一行命令完成调用
1 texts=$(tccli ocr FormulaOCR --ImageBase64 $imgbase64 --filter FormulaInfos[*].DetectedText)
然后再加上截图,base64编码,提示以及逻辑,就形成了完整的shell程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 imgpath=/tmp/tmpimg.png gnome-screenshot -a -f $imgpath if [ -f "$imgpath " ]then imgbase64=$(base64 -w 0 $imgpath ) rm $imgpath texts=$(tccli ocr FormulaOCR --ImageBase64 $imgbase64 --filter FormulaInfos[*].DetectedText) texts=$(echo $texts | xargs echo -n) texts=${texts:1:-1} texts=${texts//'\\'/'\'} echo -n $texts | xclip -selection c notify-send "公式识别成功:$texts " fi
对了,xclip 需要单独安装一下,识别结果直接放到剪贴板中是最舒服的。
emm,识别效果最后统一说吧。
百度智能云
在之前使用天若OCR 通用文字识别的时候知道它的接口是百度,然后就觉得会靠谱,也试试。
百度的逻辑会复杂一点,需要先申请个token,再拿这个token去申请服务,而且token还是有期限的,就忍不住的想要吐槽。
然后都是http调用,就很自然的给出了bash脚本
1 2 3 4 5 curl -i -k 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【百度云应用的AK】&client_secret=【百度云应用的SK】' curl -i -k 'https://aip.baidubce.com/rest/2.0/ocr/v1/formula?access_token=【调用鉴权接口获取的token】' --data 'image=【图片Base64编码,需UrlEncode】' -H 'Content-Type:application/x-www-form-urlencoded'
emm,对,因为是走的是http,所以在base64编码后又来了个urlencode,还不错有自带的 urlencode 工具。
它的token有效期是三十天整,那我的思路就是每月一号或者十五号申请一次token,保存在文件里,然后截个图识别。
就得要两段代码
1 2 3 4 5 6 7 8 9 10 11 #!/bin/bash day=$(date "+%d" ) if [[ $day == 1 || $day == 15 ]]then token=$(curl -k "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=$BAIDUCLOUD_API_KEY &client_secret=$BAIDUCLOUD_SECRET_KEY " | jq .access_token) token=${token:1:-1} echo -n $token > /home/frankchen/.baidu_access_token fi
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #!/bin/sh imgpath=/tmp/tmpimg.png gnome-screenshot -a -f $imgpath if [ -f "$imgpath " ]then imgbase64=$(base64 -w 0 $imgpath ) imgbase64=$(urlencode $imgbase64 ) rm $imgpath access_token=$(cat /home/frankchen/.baidu_access_token) texts=$(curl -k "https://aip.baidubce.com/rest/2.0/ocr/v1/formula?access_token=$access_token " --data "image=$imgbase64 " -H 'Content-Type:application/x-www-form-urlencoded' | jq .words_result | jq .[].words) texts=$(echo $texts | xargs echo -n) echo -n $texts | xclip -selection c notify-send "公式识别成功:$texts " fi
显而易见的使用了和腾讯那份类似的大框架,不过虽然都返回一个json,但是百度这边不提供解析的,需要自己从中拿。就需要额外安装一个 jq ,我这个jq参数写的比较丑。
然后识别结果同样放在最后吐槽。
讯飞开放平台
讯飞给我的感觉就很暧昧,我看了它的演示结果后决定试一试,但是随之而来的一系列绑定,强迫使用以及相对不如之前好的文档就emm
讯飞的调用规则比较复杂,参数也更加多,返回的json也更复杂,于是我决定直接白嫖讯飞提供的demo。
emm,白嫖同样是脚本语言的python3的demo,然后再在shell里调用——这点就是我特别喜欢shell的原因。
调用讯飞python3的demo命令:
1 texts=$(python3 WebITRTeach.py | jq '.data.region[] | select( has("recog") == true)' .recog.content)
json解析规则肉眼可见的复杂
全部的shell代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 imgpath=/tmp/tmpimg.png gnome-screenshot -a -f $imgpath if [ -f "$imgpath " ]then texts=$(python3 WebITRTeach.py | jq '.data.region[] | select( has("recog") == true)' .recog.content) rm $imgpath texts=$(echo $texts | xargs echo -n) texts=${texts//'ifly-latex-begin'/''} texts=${texts//'ifly-latex-end'/''} texts=${texts//'\\'/'\'} echo -n $texts | xclip -selection c notify-send "公式识别成功:$texts " fi
python3的代码就需要稍微改动一点点就可以了,而且确实有点长,就不放出来了。
Mathpix Snip
如果能用的话我就不会去考虑上边那三个了,信用卡着实劝退。
对比
实际上考研时高数笔记上大多数的公式都是我一个一个手打的,然后我现在从中拿出来几个做下对比测试。
我用妈咪说MommyTalk 制作的LaTeX公式编辑器 来代替Mathpix Snip的测试结果(毕竟它确实调用的Mathpix Snip接口)
对于个人开发者的个人使用来说,调用次数,频率什么的都完全满足个人使用需求,对比没有实际意义,因此只对识别结果进行对比。
简单组
1 2 3 4 5 6 7 8 9 10 11 \sin ( \alpha - 3 ) = \sin \cos z \sin z \sin 5sn(a+)=sinacos+cosasin \sin ( \alpha + \beta )= \sin \alpha \cos \beta + \cos \alpha \sin \beta \_ ---- -\sin (\alpha +\beta )=\sin \alpha \cos \beta +\cos \alpha \sin \beta
中等组
1 2 3 4 5 6 7 8 9 10 11 \arcsin ( \alpha ) = \frac { \triangle B \sin \gamma } { 1 } = \arcsin zt x = 1 5 0 ^ { 2 } \tan ( \alpha + \beta )= \frac {\tan \alpha +\tan \beta }{1-\tan \alpha \tan \beta } \_ . \_ \bot \tan (\alpha +\beta )=\frac {\tan \alpha +\tan \beta }{1-\tan \alpha \tan \beta }
复杂组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \arcsin \cos 2 \arcsin 2 a \cos 2 \alpha = a ^ { 2 } ) ( \sqrt { \beta ^ { 2 } + \beta ^ { 2 } } ) ( \sqrt { 2 0 2 } ) y \perp yf(x,y,z)dx+Q(x,y,z)dy+R(x,y,z)dz= \int _ {\frac {1}{2}} |_ {|} | \frac {dz}{P} dzdx dxdy ---- - C. \frac {\cos \alpha }{a^ {3}} \cos \beta \oint _ {L} P(x, y, z) d x+Q(x, y, z) d y+R(x, y, z) d z=\iint _ {\Sigma }\left |\begin {array}{ccc}d y d z & d z d x & d x d y \\ \frac {\partial }{\partial x} & \frac {\partial }{\partial y} & \frac {\partial }{\partial z} \\ P & Q & R \end {array}\right |=\iint _ {\Sigma }\left |\begin {array}{ccc}\cos \alpha & \cos \beta & \cos \gamma \\ \frac {\partial }{\partial x} & \frac {\partial }{\partial y} & \frac {\partial }{\partial z} \\ P & Q & R \end {array}\right | d S
结论
腾讯和百度搞得我心里洼凉洼凉的。
腾讯这边总是能给我识别出奇奇怪怪的公式出来,一度让我以为我记错了识别的公式。
百度这边我怀疑只是通用OCR改了个名字,完全是欺诈吧,而且调用速度还是这之间最慢的,调用次数还最少。
讯飞勉勉强强可以一战,不尽如人意,但比腾讯百度靠谱多了,还更快。
Mathpix Snip永远滴神!
尾声
其实我也试过别的接口,例如更实用的通用OCR接口,都表现十分好。但是就公式识别这一细分领域来讲,Mathpix Snip是真的棋无对手,国内的表现堪忧。
我是暂时不再有公式识别的需要了,而且也已经足够熟练,就对识别的需求不是很强烈,估计最多Mathpix Snip的学生额度就差不多了,也就暂时不考虑想办法申请信用卡进行Mathpix Snip的开发测试了。
这次的调用之旅让我一度有开发一个完整界面出来的想法,就和我之前提到的天若一样,但是用QT写,就可以很好的跨平台使用。这应该算得上是一个毕设级别的作品,但是我已经有 别的想法 ,就只能搁置了。可能什么时候再次有空了,会闲下心来做一做吧。
就这样。