如何基于Python代码实现高精度免费OCR工具


Posted in Python onJune 18, 2020

近期Github开源了一款基于Python开发、名为Textshot的截图工具,刚开源不到半个月已经500+Star。

这两天抽空看了一下Textshot的源码,的确是一个值得介绍的项目。

相对于大多数OCR工具复杂工程、差强人意的效果,Textshot具有明显的优势,

  • 项目简单
  • 技术点丰富

项目简单

Textshot整个项目只有1个Python文件、139行代码,没有复杂的第三方库应用,也不涉及过多后端算法的调用。

技术点丰富

Textshot这个项目虽然只有短短的139行代码,但是,却涉及Python中多个方面的知识应用,

  • UI开发
  • 截图工具开发
  • 后端引擎调用

通过这短短的项目,你不仅可以了解如何利用PyQt5实现一个用户界面,还可以学会如何使用pyscreenshot开发一款自己的截图工具。此外,还能够学会后端tesseract的调用。

换句话说,这短短的139行代码囊括了前端至后端的整个流程,而且涉及到截图和OCR两款工具的衔接。因此,Textshot虽然工程不大,却是一个非常完备、值得学习的项目。

本文就来剖析这个项目的源代码,教你一步一步实现自用且永久免费的截图&OCR工具!

tesseract

目前OCR工具数不胜数,但是大多数都是在相同的后端算法上面进行了不同的封装而已。而真正在OCR核心做的较好、值得大书特书的,那么一定非tesseract莫属

tesseract早在1985就已经开始由HP实验室开始研发,而在1995年更是被评为最为准确的3款OCR工具之一。此后,tesseract被开源,经过Google对其不断的进行优化和升级,它目前已经成为OCR方面一款标杆性的工具。很多开源或者付费的OCR工具,都是直接调用tesseract或者对其进行稍许优化。

而今天介绍的Textshot就是直接调用tesseract后端引擎进行OCR识别。因此,Textshot只是实现了一款截图工具,起到前后端的串联作用,在OCR识别算法方面并没有做任何工作。

tesseract安装

由于Textshot的OCR识别需要调用tesseract后端引擎,所以,首先需要安装tesseract。

Windows版安装可以直接访问下载链接[1].

Mac下可以使用Homebrew进行安装,

brew install tesseract 

Textshot

Textshot是一款截图识别文字的OCR工具,因此,它主要涉及2个环境,

截图

OCR识别

Textshot首先通过截图获取需要进行文字识别的图像,然后对这副图像进行OCR文字识别,输出识别结果。

前面已经介绍了,Textshot的OCR识别阶段调用的是tesseract,所以只需要1行代码即可完成。

因此,Textshot的工作主要是围绕前端窗口和截图工具的实现方面。

截图工具

截图工具是我们经常会用到的一种工具,如何实现一款截图工具?

很多人会把它想的非常复杂,其实,Python中有很多可以实现截图的库或者函数,例如,pyscreenshot或者pillow中的ImageGrab函数,它的调用方式如下,

shot = ImageGrab.grab(bbox=(x1, y1, x2, y2))

也就是说,我们只需要把鼠标框选的起点和终点坐标传给grab方法就可以实现截图功能。

那么,现在问题就转化为如何获取鼠标框选的起点和终点?

Textshot通过调用PyQt5并继承QWidget来实现鼠标框选过程中的一些方法来获取框选的起点和终点。

Textshot继承和重写QWidget方法主要包括如下几个,

  • keyPressEvent(self, event):键盘响应函数
  • paintEvent(self, event):UI绘制函数
  • mousePressEvent(self, event):鼠标点击事件
  • mouseMoveEvent(self, event):鼠标移动事件
  • mouseReleaseEvent(self, event):鼠标释放事件

可以看出,上面重写的方法以及囊括了截图过程中涉及的各个动作,

  • 点击鼠标
  • 拖动、绘制截图框
  • 释放鼠标
class Snipper(QtWidgets.QWidget):
  def __init__(self, parent=None, flags=Qt.WindowFlags()):
    super().__init__(parent=parent, flags=flags)
 
    self.setWindowTitle("TextShot")
    self.setWindowFlags(
      Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Dialog
    )
 
    self.is_macos = sys.platform.startswith("darwin")
    if self.is_macos:
      self.setWindowState(self.windowState() | Qt.WindowMaximized)
    else:
      self.setWindowState(self.windowState() | Qt.WindowFullScreen)
 
    self.setStyleSheet("background-color: black")
    self.setWindowOpacity(0.5)
 
    QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
 
    self.start, self.end = QtCore.QPoint(), QtCore.QPoint()
 
  def keyPressEvent(self, event):
    if event.key() == Qt.Key_Escape:
      QtWidgets.QApplication.quit()
 
    return super().keyPressEvent(event)
 
  def paintEvent(self, event):
    if self.start == self.end:
      return super().paintEvent(event)
 
    painter = QtGui.QPainter(self)
    painter.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255), 3))
    painter.setBrush(QtGui.QColor(255, 255, 255, 100))
 
    if self.is_macos:
      start, end = (self.mapFromGlobal(self.start), self.mapFromGlobal(self.end))
    else:
      start, end = self.start, self.end
 
    painter.drawRect(QtCore.QRect(start, end))
    return super().paintEvent(event)
 
  def mousePressEvent(self, event):
    self.start = self.end = QtGui.QCursor.pos()
    self.update()
    return super().mousePressEvent(event)
 
  def mouseMoveEvent(self, event):
    self.end = QtGui.QCursor.pos()
    self.update()
    return super().mousePressEvent(event)
 
  def mouseReleaseEvent(self, event):
    if self.start == self.end:
      return super().mouseReleaseEvent(event)
 
    x1, x2 = sorted((self.start.x(), self.end.x()))
    y1, y2 = sorted((self.start.y(), self.end.y()))

然后启动截图界面,

QtCore.QCoreApplication.setAttribute(Qt.AA_DisableHighDpiScaling)
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
snipper = Snipper(window)
snipper.show()

用户拖动、框选窗口,会获取窗口的起点和终点的坐标,这时候可以调用下面语句进行截图,获取需要OCR识别的文本图像,

shot = ImageGrab.grab(bbox=(x1, y1, x2, y2))

OCR文字识别

通过ImageGrab.grab截取到文本图像shot,下一步就是要把图像内容输入给后端的tesseract引擎,让它把图像转化为字符串

result = pytesseract.image_to_string(img, timeout=2, lang=(sys.argv[1] if len(sys.argv) > 1 else None))

到这里,就实现了一款准确度高、永久免费的OCR工具。

回顾一下Textshot的项目,我们会发现截图坐标范围内的图像、OCR识别只需要2行代码,大多数都是在围绕获取窗口起点和终点坐标在开发。换句话说,Textshot这个项目对OCR核心部分并没有做任何更改,只是在产品包装方面做了一些巧妙的工作。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中列表、字典、元组、集合数据结构整理
Nov 20 Python
浅析AST抽象语法树及Python代码实现
Jun 06 Python
python对excel文档去重及求和的实例
Apr 18 Python
django进阶之cookie和session的使用示例
Aug 17 Python
Python图像处理之简单画板实现方法示例
Aug 30 Python
如何在django里上传csv文件并进行入库处理的方法
Jan 02 Python
Python列表切片操作实例总结
Feb 19 Python
Python对ElasticSearch获取数据及操作
Apr 24 Python
python 爬取学信网登录页面的例子
Aug 13 Python
Python中断多重循环的几种方式详解
Feb 10 Python
django ORM之values和annotate使用详解
May 19 Python
BeautifulSoup获取指定class样式的div的实现
Dec 07 Python
python软件都是免费的吗
Jun 18 #Python
python中return如何写
Jun 18 #Python
python对一个数向上取整的实例方法
Jun 18 #Python
Python基于time模块表示时间常用方法
Jun 18 #Python
numpy 矩阵形状调整:拉伸、变成一位数组的实例
Jun 18 #Python
Numpy 多维数据数组的实现
Jun 18 #Python
python读取图像矩阵文件并转换为向量实例
Jun 18 #Python
You might like
PHP图片上传代码
2013/11/04 PHP
php中debug_backtrace、debug_print_backtrace和匿名函数用法实例
2014/12/01 PHP
PHP性能分析工具XHProf安装使用教程
2015/05/13 PHP
PHP is_array() 检测变量是否是数组的实现方法
2016/06/13 PHP
php封装的smartyBC类完整实例
2016/10/19 PHP
ThinkPHP实现生成和校验验证码功能
2017/04/28 PHP
asp.net和asp下ACCESS的参数化查询
2008/06/11 Javascript
jquery DIV撑大让滚动条滚到最底部代码
2013/06/06 Javascript
完美兼容各大浏览器获取HTTP_REFERER方法总结
2014/06/24 Javascript
输入框过滤非数字的js代码
2014/09/18 Javascript
原生Ajax 和jQuery Ajax的区别示例分析
2014/12/17 Javascript
JS实现Ajax的方法分析
2016/12/20 Javascript
JavaScript严格模式详解
2017/01/16 Javascript
AngularJS实现根据不同条件显示不同控件
2017/04/20 Javascript
vue中v-for通过动态绑定class实现触发效果
2018/12/06 Javascript
vue2.0基于vue-cli+element-ui制作树形treeTable
2019/04/30 Javascript
最简单的vue消息提示全局组件的方法
2019/06/16 Javascript
[01:08]DOTA2次级职业联赛 - Shield战队宣传片
2014/12/01 DOTA
Python 错误和异常小结
2013/10/09 Python
使用Python脚本在Linux下实现部分Bash Shell的教程
2015/04/17 Python
python 系统调用的实例详解
2017/07/11 Python
Python学生信息管理系统修改版
2018/03/13 Python
ubuntu17.4下为python和python3装上pip的方法
2018/06/12 Python
Python 支付整合开发包的实现
2019/01/23 Python
Python 硬币兑换问题
2019/07/29 Python
在VS2017中用C#调用python脚本的实现
2019/07/31 Python
python 读取串口数据的示例
2020/11/09 Python
python空元组在all中返回结果详解
2020/12/15 Python
Html5 web本地存储实例详解
2016/07/28 HTML / CSS
详解如何获取localStorage最大存储大小的方法
2020/05/21 HTML / CSS
美国购买体育、音乐会和剧院门票网站:SelectATicket
2019/09/08 全球购物
校园公益广告语
2014/03/13 职场文书
合同协议书格式
2014/04/18 职场文书
教师党员群众路线教育实践活动心得体会
2014/11/04 职场文书
2014年人力资源工作总结
2014/11/19 职场文书
CSS 实现角标效果的完整代码
2022/06/28 HTML / CSS