一款截图识别文字的OCR工具主要涉及2个环境:
前要OCR的应用场景根据OCR的应用场景而言,我们可以大致分成识别特定场景下的专用OCR以及识别多种场景下的通用OCR。就前者而言,证件识别以及车牌识别就是专用OCR的典型案例。针对特定场景进行设计、优化以达到最好的特定场景下的效果展示。那通用的OCR就是使用在更多、更复杂的场景下,拥有比较好的泛性。在这个过程中由于场景的不确定性,比如:图片背景极其丰富、亮度不均衡、光照不均衡、残缺遮挡、文字扭曲、字体多样等等问题,会带来极大的挑战。 OCR的技术路线其中OCR识别的关键路径在于文字检测和文本识别部分,这也是深度学习技术可以充分发挥功效的地方。PaddleHub为大家开源的预训练模型的网络结构是Differentiable Binarization+ CRNN,基于icdar2015数据集下进行的训练。 首先,DB是一种基于分割的文本检测算法。在各种文本检测算法中,基于分割的检测算法可以更好地处理弯曲等不规则形状文本,因此往往能取得更好的检测效果。但分割法后处理步骤中将分割结果转化为检测框的流程复杂,耗时严重。因此作者提出一个可微的二值化模块(Differentiable Binarization,简称DB),将二值化阈值加入训练中学习,可以获得更准确的检测边界,从而简化后处理流程。DB算法最终在5个数据集上达到了state-of-art的效果和性能。参考论文:Real-time Scene Text Detection with Differentiable Binarization 接着,我们使用 CRNN(Convolutional Recurrent Neural Network)即卷积递归神经网络,是DCNN和RNN的组合,专门用于识别图像中的序列式对象。与CTC loss配合使用,进行文字识别,可以直接从文本词级或行级的标注中学习,不需要详细的字符级的标注。参考论文:An end-to-end trainable neural network for image-based sequence recognition and its application to scene text recognition 下图是CRNN的网络结构图: 截图工具很多人会把它想的非常复杂,其实,Python中有很多可以实现截图的库或者函数,最常见的有三种方法。 一、Python调用windows API实现屏幕截图二、使用PIL的ImageGrab模块三、使用Selenium截图而我们需要做到的事鼠标框选范围截图,因此我们采用PyQt5和PIL实现截图功能。 我们只需要把 那么,现在问题就转化为如何获取鼠标框选的起点和终点? Textshot通过调用PyQt5并继承QWidget来实现鼠标框选过程中的一些方法来获取框选的起点和终点。 Textshot继承和重写QWidget方法主要包括如下几个,
可以看出,上面重写的方法以及囊括了截图过程中涉及的各个动作,
当然了,这一部分有现成的 可以直接使用: 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.setWindowState(self.windowState() | Qt.WindowFullScreen) self.screen = QtGui.QScreen.grabWindow( QtWidgets.QApplication.primaryScreen(), QtWidgets.QApplication.desktop().winId(), ) palette = QtGui.QPalette() palette.setBrush(self.backgroundRole(), QtGui.QBrush(self.screen)) self.setPalette(palette) 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): painter = QtGui.QPainter(self) painter.setPen(Qt.NoPen) painter.setBrush(QtGui.QColor(0, 0, 0, 100)) painter.drawRect(0, 0, self.width(), self.height()) if self.start == self.end: return super().paintEvent(event) painter.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255), 3)) painter.setBrush(painter.background()) painter.drawRect(QtCore.QRect(self.start, self.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) self.hide() QtWidgets.QApplication.processEvents() shot = self.screen.copy(QtCore.QRect(self.start, self.end)) processImage(shot) QtWidgets.QApplication.quit()def processImage(img): buffer = QtCore.QBuffer() buffer.open(QtCore.QBuffer.ReadWrite) img.save(buffer, "PNG") pil_img = Image.open(io.BytesIO(buffer.data())) buffer.close()if __name__ == '__main__': QtCore.QCoreApplication.setAttribute(Qt.AA_DisableHighDpiScaling) app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QMainWindow() snipper = Snipper(window) snipper.show() sys.exit(app.exec_()) OCR文字识别那么我们的文字识别模型选择了Paddle最新推出的OCR识别模型。改模型同时支持中英文识别;支持倾斜、竖排等多种方向文字识别。 识别文字算法采用CRNN (Convolutional Recurrent Neural Network)即卷积递归神经网络。其是DCNN和RNN的组合,专门用于识别图像中的序列式对象。与CTC loss配合使用,进行文字识别,可以直接从文本词级或行级的标注中学习,不需要详细的字符级的标注。该Module是一个通用的OCR模型,支持直接预测。 这一步我们就要做的是将截取的图片传入文字识别模型即可。 import os os.environ['HUB_HOME'] = "./modules"from PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtCore import Qtfrom PIL import Imageimport ioimport sysimport numpy as npimport paddlehub as hubclass 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.setWindowState(self.windowState() | Qt.WindowFullScreen) self.screen = QtGui.QScreen.grabWindow( QtWidgets.QApplication.primaryScreen(), QtWidgets.QApplication.desktop().winId(), ) palette = QtGui.QPalette() palette.setBrush(self.backgroundRole(), QtGui.QBrush(self.screen)) self.setPalette(palette) 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): painter = QtGui.QPainter(self) painter.setPen(Qt.NoPen) painter.setBrush(QtGui.QColor(0, 0, 0, 100)) painter.drawRect(0, 0, self.width(), self.height()) if self.start == self.end: return super().paintEvent(event) painter.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255), 3)) painter.setBrush(painter.background()) painter.drawRect(QtCore.QRect(self.start, self.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) self.hide() QtWidgets.QApplication.processEvents() shot = self.screen.copy(QtCore.QRect(self.start, self.end)) processImage(shot) QtWidgets.QApplication.quit()def processImage(img): buffer = QtCore.QBuffer() buffer.open(QtCore.QBuffer.ReadWrite) img.save(buffer, "PNG") pil_img = Image.open(io.BytesIO(buffer.data())) buffer.close() np_images = [np.array(pil_img)] results = ocr.recognize_text( images=np_images, # 图片数据,ndarray.shape 为 [H, W, C],BGR格式; use_gpu=False, # 是否使用 GPU;若使用GPU,请先设置CUDA_VISIBLE_DEVICES环境变量 output_dir='ocr_result', # 图片的保存路径,默认设为 ocr_result; visualization=True, # 是否将识别结果保存为图片文件; box_thresh=0.5, # 检测文本框置信度的阈值; text_thresh=0.5) # 识别中文文本置信度的阈值; text = [] for result in results: data = result['data'] save_path = result['save_path'] for infomation in data: print('text: ', infomation['text'], '\nconfidence: ', infomation['confidence'], '\ntext_box_position: ', infomation['text_box_position']) text.append(str(infomation['text']) + '\n') print(text) with open('data.txt', 'w') as f: for i in text: f.write(str(i)) os.system(r'data.txt')if __name__ == '__main__': # 加载移动端预训练模型 # ocr = hub.Module(name="chinese_ocr_db_crnn_mobile") # 服务端可以加载大模型,效果更好 ocr = hub.Module(name="chinese_ocr_db_crnn_server") QtCore.QCoreApplication.setAttribute(Qt.AA_DisableHighDpiScaling) app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QMainWindow() snipper = Snipper(window) snipper.show() sys.exit(app.exec_()) 那么再看一些模型的其他应用吧: AISTUDIO地址:https://aistudio.baidu.com/aistudio/projectdetail/532299?shared=1 Github地址:https://github.com/chenqianhe/screenshot_and_ocr |
|