如何基于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 正则表达式(转义问题)
Dec 15 Python
在Django的form中使用CSS进行设计的方法
Jul 18 Python
批处理与python代码混合编程的方法
May 19 Python
使用Python搭建虚拟环境的配置方法
Feb 28 Python
python 函数内部修改外部变量的方法
Dec 18 Python
Python实现将通信达.day文件读取为DataFrame
Dec 22 Python
Django unittest 设置跳过某些case的方法
Dec 26 Python
华为2019校招笔试题之处理字符串(python版)
Jun 25 Python
python+tkinter实现学生管理系统
Aug 20 Python
详细整理python 字符串(str)与列表(list)以及数组(array)之间的转换方法
Aug 30 Python
Python传递参数的多种方式(小结)
Sep 18 Python
基于Python脚本实现邮件报警功能
May 20 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 数组实例说明
2008/08/18 PHP
PHP安全性漫谈
2012/06/28 PHP
php中将html中的br换行符转换为文本输入中的换行符
2013/03/26 PHP
基于php验证码函数的使用示例
2013/05/03 PHP
php读取flash文件高宽帧数背景颜色的方法
2015/01/06 PHP
php中解析带中文字符的url函数分享
2015/01/20 PHP
编写PHP脚本使WordPress的主题支持Widget侧边栏
2015/12/14 PHP
利用Fix Rss Feeds插件修复WordPress的Feed显示错误
2015/12/19 PHP
php上传图片并压缩的实现方法
2015/12/22 PHP
使用ThinkPHP的自动完成实现无限级分类实例详解
2016/09/02 PHP
Laravel+jQuery实现AJAX分页效果
2016/09/14 PHP
PHP+原生态ajax实现的省市联动功能详解
2017/08/15 PHP
Laravel下生成验证码的类
2017/11/15 PHP
JS中剪贴板兼容性、判断复制成功或失败
2021/03/09 Javascript
JavaScript版代码高亮
2006/06/26 Javascript
jquery select(列表)的操作(取值/赋值)
2009/08/06 Javascript
jQuery 入门级学习笔记及源码
2010/01/22 Javascript
Javascript创建Silverlight Plugin以及自定义nonSilverlight和lowSilverlight样式
2010/06/28 Javascript
jquery对Json的各种遍历方法总结(必看篇)
2016/09/29 Javascript
浅述Javascript的外部对象
2016/12/07 Javascript
如何利用JQuery实现从底部回到顶部的功能
2016/12/27 Javascript
推荐三款日期选择插件(My97DatePicker、jquery.datepicker、Mobiscroll)
2017/04/21 jQuery
React组件refs的使用详解
2018/02/09 Javascript
vue首次赋值不触发watch的解决方法
2018/09/11 Javascript
防止Layui form表单重复提交的实现方法
2019/09/10 Javascript
vue+axios 拦截器实现统一token的案例
2020/09/11 Javascript
Python中tell()方法的使用详解
2015/05/24 Python
Python使用Redis实现作业调度系统(超简单)
2016/03/22 Python
使用XML库的方式,实现RPC通信的方法(推荐)
2017/06/14 Python
浅谈python str.format与制表符\t关于中文对齐的细节问题
2019/01/14 Python
利用Python实现手机短信监控通知的方法
2019/07/22 Python
很酷的小工具和电子产品商城:GearBest
2016/11/19 全球购物
高中运动会广播稿
2014/09/16 职场文书
写给父母的感谢信
2015/01/22 职场文书
建筑工程催款函
2015/06/24 职场文书
Python一些基本的图像操作和处理总结
2021/06/23 Python