diff --git a/pixelocr/gui/__init__.py b/pixelocr/gui/__init__.py index cb0847f..343b5ef 100644 --- a/pixelocr/gui/__init__.py +++ b/pixelocr/gui/__init__.py @@ -44,8 +44,8 @@ def main(): ocr = OCREngine(sys.argv[1:]) ocr.pageChanged.connect(win.pageScene.setPage) - ocr.unknownLetter.connect(win.unknownLetter) - win.letterEntered.connect(ocr.give_help) + ocr.unknownGlyph.connect(win.unknownGlyph) + win.glyphEntered.connect(ocr.give_help) ocr.start() signal.signal(signal.SIGINT, signal.SIG_DFL) diff --git a/pixelocr/gui/glyphedit.py b/pixelocr/gui/glyphedit.py index 9a44a69..134eddb 100644 --- a/pixelocr/gui/glyphedit.py +++ b/pixelocr/gui/glyphedit.py @@ -28,7 +28,7 @@ from PyQt4.QtGui import ( class GlyphEdit(QWidget): - letterEntered = signal([str]) + glyphEntered = signal([str]) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -47,11 +47,11 @@ class GlyphEdit(QWidget): self.italic.setShortcut('Ctrl+i') self.text = QLineEdit(self) - self.text.returnPressed.connect(self.sendLetter) + self.text.returnPressed.connect(self.sendGlyph) self.layout.addWidget(self.bold) self.layout.addWidget(self.italic) self.layout.addWidget(self.text) - def sendLetter(self): - self.letterEntered.emit(self.text.text()) + def sendGlyph(self): + self.glyphEntered.emit(self.text.text()) diff --git a/pixelocr/gui/ocrengine.py b/pixelocr/gui/ocrengine.py index d0dc64d..0d31da0 100644 --- a/pixelocr/gui/ocrengine.py +++ b/pixelocr/gui/ocrengine.py @@ -23,11 +23,11 @@ from PyQt4.QtCore import ( ) from ..image import Image -from ..page import Page, Letter, Space +from ..page import Page, Glyph, Space class OCREngine(QThread): - unknownLetter = signal([Letter]) + unknownGlyph = signal([Glyph]) pageChanged = signal([Page]) def __init__(self, filenames): @@ -54,21 +54,21 @@ class OCREngine(QThread): yield ''.join(self.recognize_line(line)) def recognize_line(self, line): - for letter in line.letters: - yield self.recognize_letter(letter) + for glyph in line.glyphs: + yield self.recognize_glyph(glyph) - def recognize_letter(self, letter): - if isinstance(letter, Space): + def recognize_glyph(self, glyph): + if isinstance(glyph, Space): return ' ' try: - return self.chardb[letter.key] + return self.chardb[glyph.key] except KeyError: - text = self.ask_for_help(letter) - self.chardb[letter.key] = text + text = self.ask_for_help(glyph) + self.chardb[glyph.key] = text return text - def ask_for_help(self, unknown_letter): - self.unknownLetter.emit(unknown_letter) + def ask_for_help(self, unknown_glyph): + self.unknownGlyph.emit(unknown_glyph) return self.receive_help() def give_help(self, text): diff --git a/pixelocr/gui/pageview.py b/pixelocr/gui/pageview.py index d0fe025..4fb4c7a 100644 --- a/pixelocr/gui/pageview.py +++ b/pixelocr/gui/pageview.py @@ -50,8 +50,8 @@ class PageScene(QGraphicsScene): page = None pageItem = None - letterPen = QColor(0, 0, 0, 80) - letterBrush = QColor(255, 255, 0, 80) + glyphPen = QColor(0, 0, 0, 80) + glyphBrush = QColor(255, 255, 0, 80) spacePen = QColor(0, 0, 0, 80) spaceBrush = QColor(0, 0, 255, 20) linePen = QColor(255, 50, 50, 100) @@ -60,11 +60,11 @@ class PageScene(QGraphicsScene): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.highlightedLetters = {} + self.highlightedGlyphs = {} self.setBackgroundBrush(self.palette().window()) def setPage(self, page): - self.highlightedLetters.clear() + self.highlightedGlyphs.clear() for item in self.items(): self.remoteItem(item) self.page = page @@ -78,11 +78,11 @@ class PageScene(QGraphicsScene): def highlightAll(self): for line in page: - for letter in line: - if not letter.image.isspace: - self.addRect(letter.x - 1, letter.y - 1, letter.width + 1, letter.height + 1, self.letterPen, self.letterBrush) + for glyph in line: + if not glyph.image.isspace: + self.addRect(glyph.x - 1, glyph.y - 1, glyph.width + 1, glyph.height + 1, self.glyphPen, self.glyphBrush) else: - self.addRect(letter.x - 1, letter.y - 1, letter.width + 1, letter.height + 1, self.spacePen, self.spaceBrush) + self.addRect(glyph.x - 1, glyph.y - 1, glyph.width + 1, glyph.height + 1, self.spacePen, self.spaceBrush) self.addLine(line.left, line.baseline, line.right, line.baseline, self.linePen) def addPage(self, page): @@ -90,14 +90,14 @@ class PageScene(QGraphicsScene): graphicsitem = self.addPixmap(QPixmap.fromImage(qimage)) return graphicsitem - def highlightLetter(self, letter): - rect = self.addRect(letter.x - 1, letter.y - 1, letter.width + 1, letter.height + 1, self.letterPen, self.letterBrush) - self.highlightedLetters[letter] = rect + def highlightGlyph(self, glyph): + rect = self.addRect(glyph.x - 1, glyph.y - 1, glyph.width + 1, glyph.height + 1, self.glyphPen, self.glyphBrush) + self.highlightedGlyphs[glyph] = rect def clearHighlight(self): - for item in self.highlightedLetters.values(): + for item in self.highlightedGlyphs.values(): self.removeItem(item) - self.highlightedLetters.clear() + self.highlightedGlyphs.clear() class PageView(QGraphicsView): diff --git a/pixelocr/gui/window.py b/pixelocr/gui/window.py index cff172f..de1ad5d 100644 --- a/pixelocr/gui/window.py +++ b/pixelocr/gui/window.py @@ -34,7 +34,7 @@ from .glyphedit import GlyphEdit class MainWindow(QMainWindow): - letterEntered = signal([str]) + glyphEntered = signal([str]) def __init__(self): super().__init__() @@ -46,8 +46,8 @@ class MainWindow(QMainWindow): self.page = PageView(self.pageScene, centralWidget) self.pageScene.pageItemChanged.connect(self.page.centerOnPage) self.glyphEdit = GlyphEdit(centralWidget) - self.glyphEdit.letterEntered.connect(self.letterEntered) - self.glyphEdit.letterEntered.connect(self.pageScene.clearHighlight) + self.glyphEdit.glyphEntered.connect(self.glyphEntered) + self.glyphEdit.glyphEntered.connect(self.pageScene.clearHighlight) layout = QVBoxLayout(centralWidget) layout.setSpacing(0) @@ -74,8 +74,8 @@ class MainWindow(QMainWindow): self.restoreGeometry(settings.value("windowGeometry") or b'') self.restoreState(settings.value("windowState") or b'') - def unknownLetter(self, letter): - self.pageScene.highlightLetter(letter) + def unknownGlyph(self, glyph): + self.pageScene.highlightGlyph(glyph) self.glyphEdit.setEnabled(True) self.glyphEdit.text.clear() self.glyphEdit.text.setFocus() diff --git a/pixelocr/image.py b/pixelocr/image.py index b410188..5368b1e 100644 --- a/pixelocr/image.py +++ b/pixelocr/image.py @@ -117,7 +117,7 @@ class Image(object): """Return a two-color version of the image. 0 = white (blank) pixel - 1 = black (letter) pixel + 1 = black (glyph) pixel """ grayscale = rgb2gray(self.data) diff --git a/pixelocr/page.py b/pixelocr/page.py index f4384db..3e638d5 100644 --- a/pixelocr/page.py +++ b/pixelocr/page.py @@ -84,7 +84,7 @@ class Page(PageObject): class Line(PageObject): def __iter__(self): - return iter(self.letters) + return iter(self.glyphs) @cached_property def baseline(self): @@ -97,62 +97,62 @@ class Line(PageObject): return self.y + bottom @property - def letters(self): + def glyphs(self): labels, max_label = ndimage.label(self.image.bitmap, CONNECTIVITY8) blob_slices = enumerate(ndimage.find_objects(labels, max_label), 1) - letter_images = ( + glyph_images = ( self._extract_blob(blob_slice, label, labels) for (label, blob_slice) in blob_slices ) - letters = ( - Letter(image, self.baseline - image.bottom) - for image in letter_images + glyphs = ( + Glyph(image, self.baseline - image.bottom) + for image in glyph_images ) - letters = sorted(letters, key=lambda letter: (letter.left, -letter.bottom)) - letters = self._combine_diacritics(letters) - return self._insert_spaces(letters) + glyphs = sorted(glyphs, key=lambda glyph: (glyph.left, -glyph.bottom)) + glyphs = self._combine_diacritics(glyphs) + return self._insert_spaces(glyphs) - def _optical_correction(self, letter1, letter2): - base = min(letter1.top, letter2.top) - height = max(letter1.bottom, letter2.bottom) - base - bitmap1 = np.hstack([np.ones((letter1.height, 1)), letter1.image.bitmap]) - bitmap2 = np.hstack([letter2.image.bitmap, np.ones((letter2.height, 1))]) + def _optical_correction(self, glyph1, glyph2): + base = min(glyph1.top, glyph2.top) + height = max(glyph1.bottom, glyph2.bottom) - base + bitmap1 = np.hstack([np.ones((glyph1.height, 1)), glyph1.image.bitmap]) + bitmap2 = np.hstack([glyph2.image.bitmap, np.ones((glyph2.height, 1))]) margin1 = np.zeros(height, np.int) - margin1.fill(letter1.width) + margin1.fill(glyph1.width) margin2 = np.zeros(height, np.int) - margin2.fill(letter2.width) + margin2.fill(glyph2.width) - margin1[letter1.top - base: letter1.bottom - base] = np.fliplr(bitmap1).argmax(axis=1) - margin2[letter2.top - base: letter2.bottom - base] = bitmap2.argmax(axis=1) + margin1[glyph1.top - base: glyph1.bottom - base] = np.fliplr(bitmap1).argmax(axis=1) + margin2[glyph2.top - base: glyph2.bottom - base] = bitmap2.argmax(axis=1) margins = margin1 + margin2 return margins.min() - def _combine_diacritics(self, letters): + def _combine_diacritics(self, glyphs): def is_diacritic(glyph): # XXX return ( - letter is not None + glyph is not None and glyph is not None and glyph.elevation > 5 ) - while letters: - letter, *letters = letters - diacritics = list(itertools.takewhile(is_diacritic, iter(letters))) + while glyphs: + glyph, *glyphs = glyphs + diacritics = list(itertools.takewhile(is_diacritic, iter(glyphs))) for diacritic in diacritics: - letter = Letter(letter.image.combine(diacritic.image), elevation=letter.elevation) - letters = letters[len(diacritics):] - yield letter + glyph = Glyph(glyph.image.combine(diacritic.image), elevation=glyph.elevation) + glyphs = glyphs[len(diacritics):] + yield glyph - def _insert_spaces(self, letters): - for letter, next_letter in pairwise(letters): - yield letter - if next_letter is not None: - correction = self._optical_correction(letter, next_letter) - distance = next_letter.left - letter.right + correction + def _insert_spaces(self, glyphs): + for glyph, next_glyph in pairwise(glyphs): + yield glyph + if next_glyph is not None: + correction = self._optical_correction(glyph, next_glyph) + distance = next_glyph.left - glyph.right + correction if distance > 5: - yield Space(self.image.space(letter.right, self.top, distance, self.height), self.baseline - self.top) + yield Space(self.image.space(glyph.right, self.top, distance, self.height), self.baseline - self.top) def _extract_blob(self, blob_slice, label, labels): image = self.image[blob_slice] @@ -160,17 +160,17 @@ class Line(PageObject): return image.mask(mask) -class Letter(PageObject): +class Glyph(PageObject): def __init__(self, image, elevation): super().__init__(image) self.elevation = elevation @property def key(self): - """Return a dictionary key uniquely representing this letter.""" + """Return a dictionary key uniquely representing this glyph.""" return self.elevation, self.image.tostring() -class Space(Letter): +class Space(Glyph): pass