前方高能预警,建议分多次阅读。
这里将会分成三大模块进行介绍。
1、如何使用百度AI识别的API接口进行图片文字识别;
2、如何通过使用python和win32gui进行截图;
3、如何通过使用python和win32gui进行截图,保存成图片,然后使用百度AI识别的API接口进行图片文字识别;
里面的信息量好大,建议收藏慢慢看。也感谢你的关注。
好的,下面一一进行介绍。
文章目录
一、如何使用百度AI识别的API接口进行图片文字识别
(一)自行申请注册API账号
每天可以免费使用50000次/天免费
,这个量足够我们日常使用和学习之用途了。
具体详情可以自行登录百度AI官网查看。
https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu
(二)创建应用
自行按需创建好自己的应用。
(三)获取Access Token
# encoding:utf-8
import requests
# client_id 为官网获取的AK, client_secret 为官网获取的SK
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【官网获取的AK】&client_secret=【官网获取的SK】'
response = requests.get(host)
if response:
print(response.json())
(四)调用API接口
# encoding:utf-8
import requests
import base64
'''
通用文字识别
'''
request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic"
# 二进制方式打开图片文件
f = open('[本地文件]', 'rb')
img = base64.b64encode(f.read())
params = {"image":img}
access_token = '[调用鉴权接口获取的token]'
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(request_url, data=params, headers=headers)
if response:
print (response.json())
(五)一个简单的案例
1、原图
2、部分代码
import base64
request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic"
# 二进制方式打开图片文件
f = open('222.png', 'rb')
img = base64.b64encode(f.read())
params = {"image":img}
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(request_url, data=params, headers=headers)
if response:
print (response.json())
3、输出结果
E:\Python37\python.exe D:/main01.py
{'log_id': 6305098160455157211, 'words_result_num': 4, 'words_result': [{'words': 'arrow:指定绘制直线时两端是否有箭头。该选项支持NONE(两端无箭头)、 FIRST'}, {'words': '开始端有箭头)、LAST(结束端有箭头)、BOTH(两端都有箭头)选项值。艹'}, {'words': 'arrowshape:指定箭头形状。该选项是一个形如"202010°的字符串'}, {'words': '个整数依次指定填充长度、箭头长度、箭头竞度。艹'}]}
Process finished with exit code 0
大家可以自己实操一下,百度AI识别还是非常强大的。只有自己操作了才知道。
这里其实还是比较简单的,那么下面看是就比较复杂了。
二、如何通过使用python和win32gui进行截图
(一)核心代码
无论哪种截图,这里有一个精简版的核心代码,其实就是使用ImageGrab进行图像保存。
from PIL import ImageGrab
# x1:开始截图的x坐标
# x2:开始截图的y坐标;
# x3:结束截图的x坐标
# x4:结束截图的y坐标
box = (x1, y1, x2, y2)
image = ImageGrab.grab(box)
# 保存截图文件的路径
image.save('xx.png')
OK,我们现在可以演示一下。
from PIL import ImageGrab
x1=100
y1=100
x2=300
y2=300
box = (x1, y1, x2, y2)
image = ImageGrab.grab(box)
# 保存截图文件的路径
image.save('xx.png')
运行效果:
呵呵,这个图片完全只是为了教学之用,大家不要介意啊。
(二)实现桌面截图
使用tkinter和win32gui
进行构建
1、核心代码为:
def CaptureScreen():
HWND = win32gui.GetFocus() #获取当前窗口句柄
rect=win32gui.GetWindowRect(HWND) #获取当前窗口坐标
win32gui.SetFocus(HWND)
print(rect)
rect=(0,0,root.winfo_screenwidth(),root.winfo_screenheight())
im=ImageGrab.grab(rect) #截取目标图像
im.save("second.jpeg",'jpeg') #前面一个参数是保存路径,后面一个参数是保存格式
2、完整代码为:
from tkinter import *
import win32gui
from PIL import ImageGrab
#然后是获取Canvas的实现
def CaptureScreen():
HWND = win32gui.GetFocus() #获取当前窗口句柄
rect=win32gui.GetWindowRect(HWND) #获取当前窗口坐标
win32gui.SetFocus(HWND)
print(rect)
rect=(0,0,root.winfo_screenwidth(),root.winfo_screenheight())
im=ImageGrab.grab(rect) #截取目标图像
im.save("second.jpeg",'jpeg') #前面一个参数是保存路径,后面一个参数是保存格式
root = Tk()
cv = Canvas(root, width=300, height=150)
cv.pack()
b = Button(root, text='截图', command=CaptureScreen)
b.pack()
mainloop()
运行效果就不放出来了,大家自行实验啊!
(二)实现部分截图
这里是非常复杂的一个功能。
1、整体逻辑
使用tkinter构建一个root主窗口,当用户点击截图时,创建一个toplevel窗口,然后将该窗口设置成透明模式,然后监听鼠标按键操作,同步实时生成矩形框,当鼠标再次松开的时候,就返回屏幕的位置信息,然后将该rect位置信息传递给ImageGrab进行保存。
代码如下:
im=ImageGrab.grab(rect) #截取目标图像
im.save("second.jpeg",'jpeg')#保存图像
2、相关包引入
import tkinter as tk
import win32gui
import win32api
import time
from PIL import ImageGrab
3、构建类mypartclik
其中核心部分代码如下:
def run(self):
while True:
try:
self.topwindow.update()
time.sleep(0.01)
if self.HWND_t != 0:
windowborder = win32gui.GetWindowRect(self.HWND_t)
cur_pos = win32api.GetCursorPos()
state_left_new = win32api.GetKeyState(0x01)
if state_left_new != self.state_left:
if windowborder[0] < cur_pos[0] and windowborder[2] > cur_pos[0] and windowborder[1] < cur_pos[1] and windowborder[3] > cur_pos[1]:
# print(windowborder)
# print(cur_pos)
if self.old_item != None:
self.canvas.delete(self.old_item)
self.drawline((cur_pos[0] - windowborder[0], cur_pos[1] - windowborder[1]))
else:
if (self.size != ()):
# print(self.size)
self.myquit()
self.old = ()
except Exception as e:
# print("error %r" % (e))
self.myquit()
break
return self.size
4、调用go函数实现截图
def go():
app = mypartclik(root)
size = app.run()
print(size)
image = ImageGrab.grab(size)
# 保存截图文件的路径
image.save('xx.png')
5、构建测试主程序
if __name__ == '__main__':
root = tk.Tk()
root.title('测试截图')
btn = tk.Button(root,text='截图',command=go)
btn.pack()
root.mainloop()
6、实现效果
备注:这个只是个测试程序,因此界面没有优化。
如果大家对这个截图的代码有兴趣,欢迎留言和点赞,我后续将会分享给大家。
三、如何通过使用python和win32gui进行截图,保存成图片,然后使用百度AI识别的API接口进行图片文字识别
(一)主界面
使用了之前的写字板代码:
from tkinter import *
# 导入ttk
from tkinter import ttk
from tkinter import messagebox as msgbox
from tkinter import filedialog
from collections import OrderedDict
def on_new():
text.delete(1.0,END)
def on_open():
localfile = filedialog.askopenfile(title='打开单个文件',
filetypes=[("文本文件","*.jpg"),("文本文件","*.png"),],# 只处理的文件类型
initialdir='D:/')
if(localfile):
text.delete(1.0,END)
with open(localfile.name,'r',encoding='utf-8') as f:
txt = f.readlines()
text.insert(END,txt)
else:
msgbox.showinfo(message=('读取文件异常'))
def on_save():
localfile = filedialog.asksaveasfile(title='保存文件',
filetypes=[("文本文件","*.jpg"),("文本文件","*.png"),], # 只处理的文件类型
initialdir='D:/')
if(localfile):
txt = text.get(1.0,END)
print(txt)
with open(localfile.name,'w',encoding='utf-8') as f:
f.write(txt)
else:
msgbox.showinfo(message=('读取文件异常'))
def on_exit():
root.destroy()
root =Tk()
root.title("菜单测试")
root.geometry('400x200')
text =Text(root, height=12, width=60,
foreground='darkgray',
font=('微软雅黑',12),
spacing2=8,# 设置行间距
spacing3=12)# 设置段间距
text.pack(fill=BOTH,expand=Y)
st ='Tkinter 为菜单提供了 Menu 类,该类既可代表菜单条,也可代表菜单,还可代表上下文菜单(右键菜单)。简单来说,Menu 类就可以搞定所有菜单相关内容。\n'
text.insert(END, st)
scroll =Scrollbar(text, command=text.yview)
scroll.pack(side=RIGHT, fill=Y)
# 设置text2的纵向滚动影响scroll滚动条
text.configure(yscrollcommand=scroll.set)
text.configure(state=NORMAL)
menubar =Menu(root)
root['menu']= menubar
file_menu =Menu(menubar, tearoff=0)
menubar.add_cascade(label='文件', menu=file_menu)
lang_menu =Menu(menubar, tearoff=0)
menubar.add_cascade(label='格式', menu=lang_menu)
file_menu.add_command(label="新建", command=on_new)
file_menu.add_command(label="打开", command=on_open)
file_menu.add_command(label="保存", command=on_save)
file_menu.add_separator()
file_menu.add_command(label="退出", command=on_exit)
lang_menu.add_command(label="字体", command = None)
lang_menu.add_command(label="颜色", command = None)
def popup(event):
# 在指定位置显示菜单
popup_menu.post(event.x_root, event.y_root)
def choose(x):
# 如果用户选择修改字体大小的子菜单项
if x in my_items[0].keys():
# 改变字体大小
text['font'] = ('微软雅黑', my_items[0][x])
# 如果用户选择修改颜色的子菜单项
if x in my_items[1].keys():
# 改变颜色
text['foreground'] = my_items[1][x]
def handlerAdaptor(fun, **kwds):
return lambda fun=fun, kwds=kwds: fun(**kwds)
text.bind('<Button-3>', popup)
popup_menu = Menu(text, tearoff=0)
my_items = (OrderedDict([('超大', 16), ('大', 14), ('中', 12),
('小', 10), ('超小', 8)]),
OrderedDict([('红色', 'red'), ('绿色', 'green'), ('蓝色', 'blue')]))
i = 0
for k in ['字体大小', '颜色']:
m = Menu(popup_menu, tearoff=0)
popup_menu.add_cascade(label=k, menu=m)
# 遍历OrderedDict的key(默认就是遍历key)
for im in my_items[i]:
m.add_command(label=im, command=handlerAdaptor(choose, x=im))
i += 1
root.mainloop()
(二)增加截图菜单选项
file_menu.add_command(label="截图", command=on_clip)
(三)定义图片转文字解析并插入到text文本框中
def chag(image):
client_id = 'xQ5aVGf0iRt20zP3hrV5o8ag'
client_secret = 'M4qSPdMAE7UwR8V0oytqELQs5CzEXL8I'
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%d&client_secret=%d' %(client_id,client_secret)
response = requests.get(host)
access_token = '19624546'
if response:
json1 = response.json()
access_token = json1['access_token']
request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic"
# 二进制方式打开图片文件
# f = open('222.png', 'rb')
# print(f)
# img = base64.b64encode(f.read())
img = base64.b64encode(image)
params = {"image": img}
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(request_url, data=params, headers=headers)
if response:
text.delete(1.0,END)
res = response.json()
for word in res['words_result']:
print(word['words'])
text.insert(END,word['words']+'\n')
(四)截图功能
截图不保存成文件,只是存储在内存中,然后直接通过IMAGE转二进制进行文字解析。
def on_clip():
root.iconify() # 窗口最小化
image = mypartclik.go1(root)
imgByteArr = io.BytesIO()
image.save(imgByteArr, format='JPEG')
imgByteArr = imgByteArr.getvalue()
print(imgByteArr)
chag(imgByteArr)
root.deiconify() # 还原窗口
(五)打开图片功能
打开就是只打开图片文件,并调用上面的解析方法进行解析成为文字,然后输出到文本框中。
def on_open():
localfile = filedialog.askopenfile(title='打开单个文件',
filetypes=[("文本文件","*.jpg"),("文本文件","*.png"),],# 只处理的文件类型
initialdir='D:/')
if(localfile):
chag(localfile.name,1)
else:
msgbox.showinfo(message=('读取文件异常'))
(六)实现主窗口隐藏和显示
root.iconify() # 窗口最小化
root.deiconify() # 还原窗口
(七)完整的主程序代码
from tkinter import *
from tkinter import messagebox as msgbox
from tkinter import filedialog
from collections import OrderedDict
import mypartclik
import requests
import base64
import io
def on_open():
localfile = filedialog.askopenfile(title='打开单个文件',
filetypes=[("文本文件","*.jpg"),("文本文件","*.png"),],# 只处理的文件类型
initialdir='D:/')
if(localfile):
chag(localfile.name,1)
else:
msgbox.showinfo(message=('读取文件异常'))
def on_save():
localfile = filedialog.asksaveasfile(title='保存文件',
filetypes=[("文本文件","*.txt")], # 只处理的文件类型
initialdir='D:/')
if(localfile):
txt = text.get(1.0,END)
print(txt)
with open(localfile.name,'w',encoding='utf-8') as f:
f.write(txt)
else:
msgbox.showinfo(message=('读取文件异常'))
def on_clip():
root.iconify() # 窗口最小化
image = mypartclik.go1(root)
imgByteArr = io.BytesIO()
image.save(imgByteArr, format='JPEG')
imgByteArr = imgByteArr.getvalue()
print(imgByteArr)
chag(imgByteArr,0)
root.deiconify() # 还原窗口
def chag(image,i):
client_id = '你的keyid'
client_secret = '你的client_secret_id'
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s' %(client_id,client_secret)
response = requests.get(host)
access_token = '19624546'
if response:
json1 = response.json()
access_token = json1['access_token']
request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic"
if i==1:
f = open(image, 'rb')
print(f)
img = base64.b64encode(f.read())
else:
img = base64.b64encode(image)
params = {"image": img}
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(request_url, data=params, headers=headers)
if response:
text.delete(1.0,END)
res = response.json()
for word in res['words_result']:
print(word['words'])
text.insert(END,word['words']+'\n')
def on_exit():
root.destroy()
root =Tk()
root.title("图像转文字软件V1.0")
root.geometry('600x400')
text =Text(root, height=12, width=60,
foreground='darkgray',
font=('微软雅黑',12),
spacing2=8,# 设置行间距
spacing3=12)# 设置段间距
text.pack(fill=BOTH,expand=Y)
st ='Tkinter 为菜单提供了 Menu 类,该类既可代表菜单条,也可代表菜单,还可代表上下文菜单(右键菜单)。简单来说,Menu 类就可以搞定所有菜单相关内容。\n'
text.insert(END, st)
scroll =Scrollbar(text, command=text.yview)
scroll.pack(side=RIGHT, fill=Y)
# 设置text2的纵向滚动影响scroll滚动条
text.configure(yscrollcommand=scroll.set)
text.configure(state=NORMAL)
menubar =Menu(root)
root['menu']= menubar
file_menu =Menu(menubar, tearoff=0)
menubar.add_cascade(label='文件', menu=file_menu)
lang_menu =Menu(menubar, tearoff=0)
menubar.add_cascade(label='格式', menu=lang_menu)
file_menu.add_command(label="打开", command=on_open)
file_menu.add_command(label="截图", command=on_clip)
file_menu.add_command(label="保存", command=on_save)
file_menu.add_separator()
file_menu.add_command(label="退出", command=on_exit)
lang_menu.add_command(label="字体", command = None)
lang_menu.add_command(label="颜色", command = None)
def popup(event):
# 在指定位置显示菜单
popup_menu.post(event.x_root, event.y_root)
def choose(x):
# 如果用户选择修改字体大小的子菜单项
if x in my_items[0].keys():
# 改变字体大小
text['font'] = ('微软雅黑', my_items[0][x])
# 如果用户选择修改颜色的子菜单项
if x in my_items[1].keys():
# 改变颜色
text['foreground'] = my_items[1][x]
def handlerAdaptor(fun, **kwds):
return lambda fun=fun, kwds=kwds: fun(**kwds)
text.bind('<Button-3>', popup)
popup_menu = Menu(text, tearoff=0)
my_items = (OrderedDict([('超大', 16), ('大', 14), ('中', 12),
('小', 10), ('超小', 8)]),
OrderedDict([('红色', 'red'), ('绿色', 'green'), ('蓝色', 'blue')]))
i = 0
for k in ['字体大小', '颜色']:
m = Menu(popup_menu, tearoff=0)
popup_menu.add_cascade(label=k, menu=m)
# 遍历OrderedDict的key(默认就是遍历key)
for im in my_items[i]:
m.add_command(label=im, command=handlerAdaptor(choose, x=im))
i += 1
root.mainloop()
(八)实现效果
1、打开
2、截图
四、回过头来说说核心截图类mypartclik
coding不易,且行且珍惜。
这块代码非常核心,而且也技术难度较大,因此,分享给大家,一方面希望能让大家少走弯路、希望大家能喜欢;另一方面,走过路过,点个赞、加个粉,也是彼此前进的动力!感谢!
(一)初始化需要的库
import tkinter as tk
import win32gui
import win32api
import time
from PIL import ImageGrab
(二)初始化相关参数
def __init__(self, master):
self.master=master
self.LINEWIDTH = 3
self.TRANSCOLOUR = 'gray'
self.title = 'Virtual whiteboard'
self.old = ()
self.HWND_t = 0
self.old_item = None
self.size=()
self.state_left = win32api.GetKeyState(0x01) # Left button down = 0 or 1. Button up = -127 or -128
self.initwidget()
self.initbind()
(三)初始化控件信息
def initwidget(self):
self.topwindow = tk.Toplevel(self.master)
self.topwindow.title(self.title)
self.topwindow.geometry("+0+0")
self.topwindow.lift()
self.topwindow.wm_attributes("-topmost", True)
self.topwindow.wm_attributes("-transparentcolor", self.TRANSCOLOUR)
self.topwindow.overrideredirect(1) # 去除窗口边框
self.canvas = tk.Canvas(self.topwindow, width=self.master.winfo_screenwidth(), height=self.master.winfo_screenheight())
self.canvas.pack(fill=tk.BOTH, expand=tk.Y)
self.canvas.config(cursor='tcross')
self.canvas.create_rectangle(0, 0, self.master.winfo_screenwidth(), self.master.winfo_screenheight(), fill=self.TRANSCOLOUR,
outline=self.TRANSCOLOUR)
(四)初始化事件绑定
def initbind(self):
self.topwindow.bind('<Visibility>', self.putOnTop)
self.topwindow.bind("<Any-KeyPress>", self.myquit)
self.topwindow.focus()
win32gui.EnumWindows(self.enumHandler, None)
def myquit(self,*args):
self.topwindow.destroy()
def putOnTop(self,event):
event.widget.unbind('<Visibility>')
event.widget.update()
event.widget.lift()
event.widget.bind('<Visibility>', self.putOnTop, event)
(五)实时画线框的方法
create_rectangle,可以设置边框的样式,自己可以看看我历史发过的博文。
def drawline(self,data):
if self.old !=():
self.old_item = self.canvas.create_rectangle(self.old[0], self.old[1], data[0], data[1], width=self.LINEWIDTH,outline='blue')
self.size = (self.old[0], self.old[1], data[0], data[1])
# return self.item
else:
# print(old)
self.old = (data[0], data[1])
# print(self.old)
(六)主函数run的实现
def run(self):
while True:
try:
self.topwindow.update()
time.sleep(0.01)
if self.HWND_t != 0:
windowborder = win32gui.GetWindowRect(self.HWND_t)
cur_pos = win32api.GetCursorPos()
state_left_new = win32api.GetKeyState(0x01)
if state_left_new != self.state_left:
if windowborder[0] < cur_pos[0] and windowborder[2] > cur_pos[0] and windowborder[1] < cur_pos[1] and windowborder[3] > cur_pos[1]:
# print(windowborder)
# print(cur_pos)
if self.old_item != None:
self.canvas.delete(self.old_item)
self.drawline((cur_pos[0] - windowborder[0], cur_pos[1] - windowborder[1]))
else:
if (self.size != ()):
# print(self.size)
self.myquit()
self.old = ()
except Exception as e:
# print("error %r" % (e))
self.myquit()
break
return self.size
五、尾声
终于把这么长的一篇博文写完了,其实里面的技术点非常多。下面一一分析给大家:
1、使用tkinter实现主窗口(用到了toplevel、canvas类),并用到了tkinter的原生的一些函数和方法,技术含量(两颗星),相对来说,还是蛮复杂的。
2、百度的图片转文字的API接口,虽然百度提供了相关操作文档,但是还是需要摸索,(当然,百度已经把最难的部分隐藏了,我们只需要用就好),这个我认为技术含量(1颗星),不难,但是需要摸索。
3、PIL的IMAGE操作函数(如从文件中读取图片、如从剪贴板中读取图片、图片转二进制流等等),相对来说,也是比较复杂,技术含量(两颗星)
4、实现桌面截图功能,核心模块使用了win32gui模块,这个相对来说非常难,我评估技术含量(三颗星)。
当然,上述只是我在实施过程中的个人看法,每个人观点不一样,但是上述的整理主要是为了让大家对整体有所了解和认知,并附上相关的代码,能给大家有所启发。
如果大家觉得这些还不够,我已经把代码上传到CSDN的资源中,码字不易,只求关注和分享。
努力到无能为力,拼搏到感动自己,致我们终将逝去的青春!
让我们一起共勉之!
我是俊哥,欢迎关注我的微信公众号“俊哥随笔”。
转载:https://blog.csdn.net/dhjabc_1/article/details/105787500