From f79d6da2c7fa8b9402f68df6f52244a81b3a5ac2 Mon Sep 17 00:00:00 2001 From: Andrey Golovizin Date: Mon, 18 Aug 2014 19:00:53 +0200 Subject: [PATCH] Move Image.combine() and friends to module level, add support for more than 2 images. --- pixelocr/image.py | 65 +++++++++++++++++++++++++++-------------------- pixelocr/page.py | 7 +++-- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/pixelocr/image.py b/pixelocr/image.py index 5368b1e..4e24ff2 100644 --- a/pixelocr/image.py +++ b/pixelocr/image.py @@ -14,6 +14,7 @@ # along with this program. If not, see . +import itertools from io import BytesIO import numpy as np @@ -23,6 +24,42 @@ from skimage.color import rgb2gray from .utils import cached_property, pairwise +def bbox(*images): + return ( + min(image.left for image in images), + min(image.top for image in images), + max(image.right for image in images), + max(image.bottom for image in images), + ) + + +def overlap(*images): + for image1, image2 in itertools.combinations(images, 2): + xoverlap = (image1.right > image2.left and image2.right > image1.left) + yoverlap = (image1.bottom > image2.top and image2.bottom > image1.top) + if xoverlap and yoverlap: + return True + return False + + +def combine(*images): + if overlap(*images): + raise NotImplementedError + + left, top, right, bottom = bbox(*images) + width = right - left + height = bottom - top + + data = np.zeros((height, width, images[0].data.shape[2]), images[0].data.dtype) + data.fill(255) + + for image in images: + xoffset = image.left - left + yoffset = image.top - top + data[yoffset:yoffset + image.height, xoffset:xoffset + image.width] = image.data + return Image(data, left, top) + + def _is_nonblank(bitmap): """Return True if bitmap contains at least one black (=1) pixel.""" return bitmap.any() @@ -167,34 +204,6 @@ class Image(object): data = np.ma.masked_array(self.data, mask3, fill_value=255).filled() return Image(data, self.x, self.y) - def bbox(self, other): - return ( - min(self.left, other.left), - min(self.top, other.top), - max(self.right, other.right), - max(self.bottom, other.bottom), - ) - - def overlaps(self, other): - return not (self.right < other.left or other.left < self.right) - - def combine(self, other): - if self.overlaps(other): - raise NotImplementedError - - left, top, right, bottom = self.bbox(other) - width = right - left - height = bottom - top - selftop = self.top - top - othertop = other.top - top - selfleft = self.left - left - otherleft = other.left - left - data = np.zeros((height, width, self.shape[2]), self.data.dtype) - data.fill(255) - data[selftop:selftop + self.height, selfleft:selfleft + self.width] = self.data - data[othertop:othertop + other.height, otherleft:otherleft + other.width] = other.data - return Image(data, left, top) - def _iter_lines(self, min_space): def iter_lines(): line_start = None diff --git a/pixelocr/page.py b/pixelocr/page.py index 1bd3911..90869e2 100644 --- a/pixelocr/page.py +++ b/pixelocr/page.py @@ -22,7 +22,7 @@ from scipy import ndimage from scipy.ndimage import filters from .utils import cached_property, collect_iterable, pairwise -from .image import Image +from .image import Image, combine CONNECTIVITY8 = ndimage.generate_binary_structure(2, 2) @@ -196,9 +196,8 @@ class Glyph(PageObject): def add_diacritics(self, *diacritics): if not diacritics: return self - if len(diacritics) > 1: - raise NotImplementedError - return Glyph(self.image.combine(diacritics[0].image), self.elevation) + diacritic_images = (diacritic.image for diacritic in diacritics) + return Glyph(combine(self.image, *diacritic_images), self.elevation) class Space(Glyph):