自制 Windows 小工具 ———— 文字识别助手

  • 背景
  • 问题分析
  • 工具准备
  • 第一部分:屏幕截图的实现
  • 文字识别
  • 结果展示
  • 保持原格式
  • 事件绑定

背景

使用电脑的时候经常遇到图片上满是文字,想复制却有心无力的情况。又或者浏览器不允许复制这样的恶心设置。
什么?你说微信QQ都有这样的工具?难道你要为了一个简单的文字提取而专门登录这样的重器?又或者网络被小偷偷走了呢?

问题分析

其实这个功能能主要包括两个方面的内容

  1. 屏幕截图(选择要复制的内容)
  2. 文字识别

我们依次实现就好了

工具准备

  • python(建议3.10.4,亲测这个版本匹配cnocr没有问题)
  • cnocr (python 第三方库)
  • pyautogui (python 第三方库)

python自己准备,这里不做多余的讲述。
pyautogui,cnocr直接pip install pyautogui pip install cnocr即可
一定要找一个有免费网络的地方,不要用手机流量哦,后面有重磅炸弹
第一次安装cnocr后,win + r打开cmd,运行python然后输入from cnocr import CnOcr,第一次他会下载文字识别包。
这里有个提示,如果网络中断了,那么下一次再打开,他就会报错。
解决方法也很简单,只需要根据报错信息的第1行(注意去掉最后的文件名)找到下载路径删除下载了一半的zip文件,然后再重新下载就好了

第一部分:屏幕截图的实现

屏幕截图的话,我们使用pyautogui.screenshot()就好,可以传入左上角坐标和宽高控制区域
关键是获取用户选择的区域
一个可行的方法是用tkinter创建透明窗口,让用户既可以看见桌面,我们也可以获取鼠标事件
因为要多次调用,方便起见,我们封装一个模块 Screencut.py

import tkinter as tk
import pyautogui
import time#鼠标左键按下
def button_1(event):global x, y ,xstart,ystartx, y = event.x, event.yxstart,ystart = event.x, event.yxstart,ystart = event.x, event.y  cv.configure(height=1)cv.configure(width=1)cv.place(x=event.x, y=event.y)#鼠标左键按下并移动
def b1_Motion(event):global x, yx, y = event.x, event.yglobal cvcv.configure(height = event.y - ystart)cv.configure(width = event.x - xstart)#鼠标左键松开
def buttonRelease_1(event):global x, y,xstart,ystartx, y = event.x, event.yif x == xstart and y == ystart:returnglobal cvglobal rootPstart=[0,0]cv.place_forget()root.attributes("-alpha", 0) img = pyautogui.screenshot(region=[xstart,ystart,x-xstart,y-ystart]) # x,y,w,himg.save('screenshot.png')sys_out()# 退出
def sys_out(even = True):global root#from tkinter import messagebox#if messagebox.askokcancel('Exit','Confirm to exit?'):root.destroy()def GetPic():global rootroot = tk.Tk()root.overrideredirect(True)         # 隐藏窗口的标题栏# root.attributes("-alpha", 0.3)    # 窗口透明度70 %root.attributes("-alpha", 0.3)      # 窗口透明度60 %root.attributes("-topmost", 1)#root.geometry("300x200+10+10")      # 设置窗口大小与位置root.geometry("{0}x{1}+0+0".format(root.winfo_screenwidth(), root.winfo_screenheight()))root.configure(bg="black")# 再创建1个Canvas用于圈选global cv, x, y, xstart, ystartcv = tk.Canvas(root)x, y = 0, 0xstart,ystart = 0 ,0# 绑定事件到Esc键,当按下Esc键就会调用sys_out函数,弹出对话框root.bind('<Escape>',sys_out)root.bind("<Button-1>", button_1)root.bind("<B1-Motion>", b1_Motion)root.bind("<ButtonRelease-1>", buttonRelease_1)root.mainloop()

思路难度不大,按部就班的走就好,自行看代码理解,每次调用GetPic()会弹出窗口让用户选择,并且将截好的图片保存在screenshot.png

文字识别

有了图片,下一步就是文字识别了。
模式很简单,传入screenshot.png,返回一个识别结果的列表,不会使用cnocr的同学自行百度,也可以直接看代码,非常简单,因为是功能的主体,所以放到主程序中,就叫TextOCR.py

from cnocr import CnOcr
import screenshot # 自己封装的功能
def TextOCR():                 ScreenCut.GetPic() # 首先调用GetPic获取截图ocr = CnOcr() # 调用识别工具result = ocr.ocr('screenshot.png') # 返回识别结果的列表print(result) # 输出

咦?怎么输出了一堆奇怪的数组
有python经验的你看出来了吗?我们需要手动提取这里的结果
但是别慌,后面还有重头戏,这个暂且放一放

结果展示

为了方便用户,我们还是用tkinter把它显示出来
还是先封装一个功能模块 ShowResult.py

import tkinter as tkdef show(text): # 给到每一行的文字列表,一行一行的显示到文本框root = tk.Tk()root.title('GWord')root.attributes("-topmost", 1) # 这里给到一个置顶,方便用户查看+txt_area = tk.Text(root,wrap="none") # 设置到文本框结尾不自动换行for i in range(len(text)):txt = text[i].strip("\n")txt_area.insert(tk.END,txt)if i != len(text) - 1:txt_area.insert(tk.END,"\n")txt_area.pack()root.mainloop()

保持原格式

这是这里头的最有技术含量,也是最值得研究的地方了。希望本文抛砖引玉,有想法的朋友可以评论与我讨论哦
注意到result中除了'text'属性,还有一个坐标数组表示这个文字的四角坐标,我们通过这个来保留原格式。
这里有个疑问请朋友们知道的个我留言哦:为什么两个左右相差很远的文字,他们的横坐标几乎是相同的呢?且有的时候相较于左右更近的文字,离的远的文字反而差值更小呢?
先忽略这个情况,我们默认左右顺序在返回的数组中已保持相对顺序(即在左边的原本的index也更靠前)
先让一个文字的x坐标为四个x坐标中的最小值(当然这个不影响),y坐标为四个坐标的平均值
然后我们对y坐标排序,先给定一个阈值,经测试 15 15 15是被较好的,我们用DES保存这个数值,方便调整,然后排序,TextOCR.py对刚才的代码进行了改善

from cnocr import CnOcr
import ScreenCut
import ShowResult
from functools import cmp_to_key
import osDES = 15def Data(res):px = 1e9py = 0for pos in res["position"]:px = min(px,pos[0])py += pos[1]py /= len(res["position"])return {"x":px,"y":py,"text":res["text"]}def cmp(a,b):global DESif abs(a["y"] - b["y"]) < DES:return 0return a["y"] - b["y"]def TextOCR():global DESScreenCut.GetPic()ocr = CnOcr()result = ocr.ocr('screenshot.png')text = []positionlist = []for i in range(len(result)):positionlist.append(Data(result[i]))positionlist.sort(key = cmp_to_key(cmp))if len(positionlist) != 0:text.append(positionlist[0]["text"])for i in range(1,len(positionlist)):if abs(positionlist[i]["y"] - positionlist[i - 1]["y"]) < DES: # 判断在同一行,追加到结尾text[-1] += " " + positionlist[i]["text"]else:text.append(positionlist[i]["text"])ShowResult.show(text)os.remove('screenshot.png') # 我们把使用完的照片删除掉,保护隐私

事件绑定

然后我们同过keyboard库来绑定鼠标事件(这里绑定ctrl + alt貌似这是几个为数不多的没有被各大应用程序占领的快捷键,好不容易试出来的),还是在TextOCR.py

from cnocr import CnOcr
import ScreenCut
import ShowResult
import keyboard
from functools import cmp_to_key
import osDES = 15def Data(res):px = 1e9py = 0for pos in res["position"]:px = min(px,pos[0])py += pos[1]py /= len(res["position"])return {"x":px,"y":py,"text":res["text"]}def cmp(a,b):global DESif abs(a["y"] - b["y"]) < DES:return 0return a["y"] - b["y"]def TextOCR():global DESScreenCut.GetPic()ocr = CnOcr()result = ocr.ocr('screenshot.png')text = []positionlist = []for i in range(len(result)):positionlist.append(Data(result[i]))positionlist.sort(key = cmp_to_key(cmp))if len(positionlist) != 0:text.append(positionlist[0]["text"])for i in range(1,len(positionlist)):if abs(positionlist[i]["y"] - positionlist[i - 1]["y"]) < DES:text[-1] += " " + positionlist[i]["text"]else:text.append(positionlist[i]["text"])ShowResult.show(text)os.remove('screenshot.png')if __name__ == '__main__':keyboard.add_hotkey('alt+ctrl',TextOCR)keyboard.wait()

这里提出一个问题
有朋友知道cnocr怎么打包成exe,pyinstaller貌似不能把那个资源文件也打包进去,会出错
感谢评论区或私信回答

这里再补充一个问题(相当于一个提醒)
在复制窗口中的文字时一定要等到ctrl + c,然后到目标位置ctrl+v后再关闭窗口,不然其他程序会死机(死机后关闭这个程序,另外的死机窗口也好了)
有朋友知道问什么吗?
感谢评论区或私信回答

接下来给一张效果图

自制 Windows 小工具 ———— 文字识别助手相关推荐

  1. 自制 Windows 小工具 ———— 智能截屏工具

    自制 Windows 小工具 ---- 智能截屏工具 背景 需求分析 环境准备 功能实现 获取截图区域 获取文件保存路径 图像算法 截屏 快捷启动 背景 上网课期间,很多同学(包括老师)都会选择(提倡 ...

  2. 自制python小工具(3)——Gadgets1.1

    自制python小工具(3)--Gadgets 1.1 文章目录 自制python小工具(3)--Gadgets 1.1 1. 前言 2. 功能实现 2.1 主程序界面 2.1.1 标签与按钮 2.1 ...

  3. WinMount是一款国产免费且功能强大Windows小工具,具备压缩解压和虚拟光驱(CD/DVD)的双重功能...

    http://cn.winmount.com/index.html WinMount是一款国产免费且功能强大Windows小工具,具备压缩解压和虚拟光驱(CD/DVD)的双重功能.最大特色在于压缩包虚 ...

  4. [分享] jQuery开发之windows边栏小工具开发(Gadget development)- windows小工具实现的公司内部分机查询工具...

    作者:Terry li - GBin1.com 使用vista和win7的朋友可能都或多或少的使用过windows小工具,这些小工具可以被自由的添加到桌面上并且快速实现一定的功能,比如,天气预报,股票 ...

  5. 自制python小工具(2)——Gadgets 0.2

    自制python小工具(2)--Gadgets 0.2 文章目录 自制python小工具(2)--Gadgets 0.2 1. 前言 1.1 上篇 2. Gadgets 0.2更新功能介绍 3. Ga ...

  6. 优秀公众号推荐 STM32与FPGA资料整理 windows小工具推荐

    文章目录 学习公众号推荐(无广告,良心推荐) 1.工具类 1.网罗灯下黑 2.平凡而诗意(这个老哥应该是弄深度学习的,整理的资料挺不错的,下面也还会推荐一次~) 3.Topbook 2.硬件类 1.吴 ...

  7. Python——【自制搜索小工具】

    哈喽,大家好丫,你们的小郭子又来啦 ~ 当自己电脑文件很多还有点乱,用电脑自带的搜索文件,效率有点低,憋担心,我们用Python自制一个搜索小工具就行了,嘻嘻嘻嘻 环境准备 解释器: Python 3 ...

  8. 推荐几个 Windows 小工具

    新的一年,抽空管理一下 Windows 里的文件.发现有的小工具用了两年以上了,也顺便推荐一下,是不是有些"火星"我倒真不知道,但总会对有些朋友有帮助的吧? PathSync 目录 ...

  9. windows小工具大全

    今天又给大家推荐一款windows的工具神器哦~~~~,快来尝鲜吧!!! 核心工具箱(PC端) 这是一款功能很强大,并且集合了多家神器于一身的软件,软件可以jihuo系统.GIF录屏.看各种电影.不限 ...

最新文章

  1. API网关是否真的起到了它该有的作用?
  2. R语言ggplot2绘制平滑曲线的折线图简单小例子
  3. C++中String类的实现
  4. SPH(光滑粒子流体动力学)流体模拟实现四:各向异性(Anisotropic)表面光滑(2)
  5. 1、图解Oracle Logminer配置使用
  6. 解决批处理命令执行完毕后自动关闭cmd窗口
  7. 内存溢出的危害_漏洞练习之网络编程与堆栈溢出技术
  8. oracle及mysql错误记录
  9. STM32 F7xx + LAN8720+LWIP1.4.1调试坑点记录
  10. TVS 瞬态抑制二极管如何选型?
  11. 用python开发手机游戏_python开发安卓app
  12. wpl计算方法_用于计算加权路径长度(WPL)的C ++二叉树算法
  13. hotmail邮箱登录服务器,hotmail邮箱登录页面在哪 hotmail邮箱账号登录设置教程
  14. 从程序员到技术总监:一个普通人13年的奋斗
  15. 小程序源码:装B神器P图修改微信流量主小程序源码下载趣味恶搞图制作
  16. java8 stream中Comparator.comparing排序
  17. LDA模型中文文本主题提取丨可视化工具pyLDAvis的使用
  18. 哪款文件比较软件适合程序员
  19. Zigzag小整数压缩算法
  20. Web安全攻防 信息收集篇(仅供交流学习使用,请勿用于非法用途)

热门文章

  1. Chrome 浏览器 Adobe Flash Plugs 过期
  2. SKIL/工作流程/命令行
  3. 服务器SMP、NUMA、MPP体系学习笔记。
  4. 计算机科学与技术研究热点,计算机科学前沿热点及发展趋势.pdf
  5. 基于Anaconda安装环境的OpenCV机器视觉环境搭建
  6. windows 8 应用商店揭秘(推荐)
  7. 斜杠青年Ruff:区块链只是分内事 1
  8. 后盾网-CI框架实例教程-马振宇 - 学习笔记(5)
  9. 博弈——Wizards and Numbers
  10. SPOT2卫星数据介绍