diff --git a/pixelocr/gui/__init__.py b/pixelocr/gui/__init__.py index 0e8e670..a659f7c 100644 --- a/pixelocr/gui/__init__.py +++ b/pixelocr/gui/__init__.py @@ -28,10 +28,16 @@ from PyQt4 import QtCore QtCore.signal = QtCore.pyqtSignal QtCore.slot = QtCore.pyqtSlot +from PyQt4.QtCore import ( + QThread, +) + from PyQt4.QtGui import ( + qApp, QApplication, ) +from .guiproxy import GUIProxy from .window import MainWindow from .ocrengine import OCREngine @@ -51,6 +57,18 @@ def load_entry_point(group, name): raise ValueError('Entry point {} in group {} not found'.format(name, group)) +class WorkerThread(QThread): + def __init__(self, ocr, quit=False): + super().__init__() + self.ocr = ocr + self.quit = quit + + def run(self): + self.ocr.recognize() + if self.quit: + qApp.quit() + + def main(): app = QApplication(sys.argv) @@ -58,19 +76,21 @@ def main(): QApplication.setApplicationName("PixelOCR"); args = parser.parse_args() + gui_proxy = GUIProxy() ocr = OCREngine( args.filename, + ui=gui_proxy, skip=args.skip, limit=args.limit, - quit=args.quit, output_format=load_entry_point('pixelocr.formatting', args.output_format).load()(), ) app.aboutToQuit.connect(ocr.save_glyphdb) + ocr_thread = WorkerThread(ocr, quit=args.quit) win = MainWindow(ocr) - win.glyphEntered.connect(ocr.give_help) + win.glyphEntered.connect(gui_proxy.give_help) win.show() - ocr.start() + ocr_thread.start() signal.signal(signal.SIGINT, signal.SIG_DFL) sys.exit(app.exec_()) diff --git a/pixelocr/gui/guiproxy.py b/pixelocr/gui/guiproxy.py new file mode 100644 index 0000000..325c05f --- /dev/null +++ b/pixelocr/gui/guiproxy.py @@ -0,0 +1,55 @@ +# Copyright (C) 2014 Andrey Golovizin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +from queue import Queue + +from PyQt4.QtCore import ( + signal, + slot, + QObject, +) + +from PyQt4.QtGui import ( + qApp, +) + +from ..ui import BaseUI +from ..page import Page, Glyph + + +class GUIProxy(QObject, BaseUI): + unknownGlyph = signal([Glyph, bool, bool]) + pageChanged = signal([Page]) + + def __init__(self): + super().__init__() + self.help_queue = Queue() + + def turn_page(self, page): + self.pageChanged.emit(page) + + def process_events(self): + qApp.processEvents() + + def ask_for_help(self, unknown_glyph): + self.unknownGlyph.emit(unknown_glyph, self.last_style.bold, self.last_style.italic) + return self.receive_help() + + def give_help(self, *args): + self.help_queue.put(args) + + def receive_help(self): + return self.help_queue.get() diff --git a/pixelocr/gui/ocrengine.py b/pixelocr/gui/ocrengine.py index 7761f80..34b3e57 100644 --- a/pixelocr/gui/ocrengine.py +++ b/pixelocr/gui/ocrengine.py @@ -17,35 +17,22 @@ import itertools from glob import glob from os import path -from queue import Queue - -from PyQt4.QtCore import ( - signal, - slot, - QThread, -) -from PyQt4.QtGui import ( - qApp -) from .. import formatting from ..image import Image -from ..page import Page, Glyph, Space +from ..page import Page, Space from ..glyphdb import GlyphDB, SPACE, NEWLINE -class OCREngine(QThread): +class OCREngine(object): SPACE_WIDTH = 15 - unknownGlyph = signal([Glyph, bool, bool]) - pageChanged = signal([Page]) - def __init__(self, dirname, skip=0, limit=None, quit=False, output_format='text'): + def __init__(self, dirname, ui, skip=0, limit=None, output_format='text'): super().__init__() self.dirname = dirname + self.ui = ui self.filenames = sorted(glob(path.join(dirname, '*.png')))[skip:skip + limit if limit else None] self.glyphdb = GlyphDB(path.join(self.dirname, 'glyphdb.pickle')) - self.help_queue = Queue() - self.quit = quit self.output_format = output_format self.last_style = (False, False, (255, 255, 255)) # FIXME get rid of hardcoded value @@ -55,15 +42,10 @@ class OCREngine(QThread): def load_page(self, filename): return Page(Image.fromfile(filename), filename) - def run(self): - self.recognize() - if self.quit: - qApp.quit() - def recognize(self): for filename in self.filenames: page = self.load_page(filename) - self.pageChanged.emit(page) + self.ui.turn_page(page) page_text = self.recognize_page(page) print(page_text) with open(filename + self.output_format.suffix, 'w') as page_text_file: @@ -80,24 +62,15 @@ class OCREngine(QThread): yield NEWLINE def recognize_glyph(self, glyph): - qApp.processEvents() + self.ui.process_events() if isinstance(glyph, Space): return SPACE try: glyph_data = self.glyphdb[glyph] except KeyError: - text, bold, italic = self.ask_for_help(glyph) + text, bold, italic = self.ui.ask_for_help(glyph) glyph_data = self.glyphdb.add_glyph(glyph, text, bold, italic) self.last_style = glyph_data.style return glyph_data - def ask_for_help(self, unknown_glyph): - self.unknownGlyph.emit(unknown_glyph, self.last_style.bold, self.last_style.italic) - return self.receive_help() - - def give_help(self, *args): - self.help_queue.put(args) - - def receive_help(self): - return self.help_queue.get() diff --git a/pixelocr/gui/window.py b/pixelocr/gui/window.py index e48f46e..798f3ec 100644 --- a/pixelocr/gui/window.py +++ b/pixelocr/gui/window.py @@ -59,9 +59,9 @@ class MainWindow(QMainWindow): self.glyphEdit.glyphEntered.connect(self.unknownGlyphEntered) self.glyphEdit.glyphEntered.connect(self.pageScene.clearHighlight) self.glyphEdit.glyphEntered.connect(self.glyphDBEdit.updateData) - ocr.pageChanged.connect(self.pageScene.setPage) - ocr.pageChanged.connect(self.showPageTitle) - ocr.unknownGlyph.connect(self.unknownGlyph) + ocr.ui.pageChanged.connect(self.pageScene.setPage) + ocr.ui.pageChanged.connect(self.showPageTitle) + ocr.ui.unknownGlyph.connect(self.unknownGlyph) self.page.setFocusProxy(self.glyphEdit) layout = QVBoxLayout(centralWidget) diff --git a/pixelocr/ui.py b/pixelocr/ui.py new file mode 100644 index 0000000..ec4a0b1 --- /dev/null +++ b/pixelocr/ui.py @@ -0,0 +1,25 @@ +# Copyright (C) 2014 Andrey Golovizin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +class BaseUI(object): + def ask_for_help(self, unknown_glyph): + raise NotImplementedError + + def turn_page(self, page): + pass + + def process_events(self): + pass