前言
天若ocr是我用过最满意的一个文字识别工具,它最核心的功能就是聚合了多个api识别接口。经过我的试验,我发现百度云的ocr是准确率最高的,而且它的免费额度也非常多。通用文字识别一天可免费调用50000次,高精度文字识别一天也有500次的免费额度。此外,还可以开工单申请开通表格文字识别,它也有50次/天的免费额度,个人使用绰绰有余。唯一的缺憾就是没有公式识别,只能寻找其他方案。试过腾讯云和有道云,二者的效果都不能让人满意,只有Mathpix
能够应付我的需求,可惜也信用卡才能开通相应的接口。不过这都是题外话了,今天我就来教大家怎么通过python,来实现与天若ocr类似的功能。
思路
天若ocr的使用流程是:按下快捷键——开始截图——截图完成后上传至百度云进行识别——返回结果,那我们就按照这个流程来做。
监听键盘按键
在网上找了一下,能够实现这种功能的库有pyHook
,PyWin32
和pyninput
,一个个尝试下来,pyHook
过于卡顿,PyWin32
有点麻烦,学习成本高,所以最终我选择了pyninput
。
它的功能也很简单:监听键盘或鼠标按键,控制键盘或鼠标按键。我们可以用它来监听用户按下截图快捷键win+shift+s
,然后进行后续操作。理论上可行,但是操作起来就发现一个大问题:这个库没法监听组合按键!(可能可以,但是我实在找不到如何实现这样的效果)。冥思苦想了一阵,突然发现我思路跑偏了,为什么要监听截图快捷键?万一用户只是用来截个图发微信呢?应该监听一个特定的键(比如F7
),如果用户按下这个键,那么代表着用户想要使用文字识别功能,此时再用pyninput
控制键盘按下win+shift+s
(对,虽然无法监听组合按键,但是可以控制组合按键),然后截图,进行后续流程……
顺着这个思路,写出了相应的代码。
from pynput.keyboard import Key,Controller,Listener
def on_press(key):
pass
# print('{0} pressed'.format(key))
def on_release(key):
# print('{0} release'.format(key))
keyboard = Controller()
if key == Key.f7:
keyboard.press(Key.cmd)
keyboard.press(Key.shift)
keyboard.press('s')
keyboard.release(Key.shift)
keyboard.release(Key.cmd)
keyboard.release('s')
if key == Key.esc:
# Stop listener
return False #停止监视
def main():
with Listener(on_press=on_press,on_release=on_release) as listener:
listener.join()
if __name__ == '__main__':
main()
这样就实现了最基础的功能:按下F7,开始截图。
获取截图并判断
截完图后上传,思路是获取剪贴板中的图片,然后提交给百度api。
获取截图很简单,PIL
库中有个模块ImageGrab
,它的一个函数就是用来获取剪贴板图片。不过应该再做一个判断,万一剪贴板的内容不是图片呢?可以利用另外一个模块Image
,来判断是否为图片。
接下来又是一个难点:我怎么判断应该什么时候获取剪贴板图片并上传呢?
一个直观的想法就是结合pynput
库,当用户按下F7的时候进入判定,设一个条件为用户松开鼠标,此时截图肯定已经完成了,就可以上传。但是我实际操作起来,发现并不能实现这一点,不知道是哪里出问题了,只能加一个time()条件,截图开始后几秒后获取剪贴板图片并上传。如果您能解决这一问题,欢迎评论留言给我。
这块代码如下:
import time
time.sleep(2)
pic = ImageGrab.grabclipboard()
if isinstance(pic, Image.Image):
pic.save('testpic.png')
with open("testpic.png", 'rb') as f:
image_data = f.read()
words = ocr(image_data)
for word in words:
print(word)
上传截图并识别
这块代码就是上面的ocr
函数,虽然是最核心的内容,但是实现起来也是最简单的。根据百度云的文档,首先要获取token
,然后才能使用api
。当然,你可以手动获取token
,但是官方称它会30天一变,为了长期使用最好还是自动生成。
另外,根据文档,上传的图片都需要base64编码,所以还需要进行urlencode
。返回的结果是json格式,也需要写个循环进行读取。
具体文档可参考
代码如下:
import requests
import base64
import urllib
import json
client_id ='填入你自己的client_id'
client_secret ='填入你自己的client_secret'
#获取token
def get_token(): # 获取你的token
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + client_id + '&client_secret=' + client_secret
request = urllib.request.Request(host)
request.add_header('Content-Type', 'application/json; charset=UTF-8')
response = urllib.request.urlopen(request)
token_content = response.read()
if token_content:
token_info = json.loads(token_content)
token_key = token_info['access_token']
return token_key
def ocr(image_data): # ocr识别函数
base64_ima = base64.b64encode(image_data)
access_token=get_token()
data = {
'image': base64_ima
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=" + str(access_token)
result = requests.post(url, params=headers, data=data).json()
for word in result['words_result']:
yield word['words']
如何获取client_id和client_secret?
首先,注册一个百度账号,进入百度云ocr管理界面。
点击创建应用
填写相关内容(随便填)
创建完成后,点击查看应用
,或在主界面点击管理应用
,就可以看到你的client_id(API key
)和client_secret(Secret Key
)了。
代码
以上代码整理如下:
import requests
import base64
import urllib
import json
from PIL import Image, ImageGrab
from pynput.keyboard import Key,Controller,Listener
import time
client_id ='填入你的API Key'
client_secret ='填入你的Secret Key'
#获取token
def get_token():
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + client_id + '&client_secret=' + client_secret
request = urllib.request.Request(host)
request.add_header('Content-Type', 'application/json; charset=UTF-8')
response = urllib.request.urlopen(request)
token_content = response.read()
if token_content:
token_info = json.loads(token_content)
token_key = token_info['access_token']
return token_key
def ocr(image_data): # ocr识别函数
base64_ima = base64.b64encode(image_data)
access_token=get_token()
data = {
'image': base64_ima
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=" + str(access_token)
result = requests.post(url, params=headers, data=data).json()
for word in result['words_result']:
yield word['words']
def on_press(key):
pass
# print('{0} pressed'.format(key))
def on_release(key):
# print('{0} release'.format(key))
keyboard = Controller()
if key == Key.f7:
keyboard.press(Key.cmd)
keyboard.press(Key.shift)
keyboard.press('s')
keyboard.release(Key.shift)
keyboard.release(Key.cmd)
keyboard.release('s')
time.sleep(2)
pic = ImageGrab.grabclipboard()
if isinstance(pic, Image.Image):
pic.save('testpic.png')
with open("testpic.png", 'rb') as f:
image_data = f.read()
words = ocr(image_data)
for word in words:
print(word)
if key == Key.esc:
# Stop listener
return False #停止监视
def main():
with Listener(on_press=on_press,on_release=on_release) as listener:
listener.join()
if __name__ == '__main__':
main()
版权属于:作者名称
本文链接:https://www.sitstars.com/archives/39/
转载时须注明出处及本声明