Add image.SubImage, move page-related logic to page.* classes.
This commit is contained in:
parent
e3a68c3043
commit
b5194ca018
2 changed files with 143 additions and 39 deletions
|
|
@ -31,42 +31,70 @@ def _is_nonblank(bitmap):
|
||||||
class Image(object):
|
class Image(object):
|
||||||
"""Basic image class."""
|
"""Basic image class."""
|
||||||
|
|
||||||
child_cls = None
|
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self._data = data
|
self.parent = self
|
||||||
|
self.data = data
|
||||||
|
self.y1 = 0
|
||||||
|
self.y2 = self.width
|
||||||
|
self.x1 = 0
|
||||||
|
self.x2 = self.height
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return type(self)(self._data.__getitem__(key))
|
"""Return a SubImage for the specified region."""
|
||||||
|
|
||||||
|
def indices(sliceobj, length):
|
||||||
|
"""Decode a slice object and return a pair of end:start indices."""
|
||||||
|
if sliceobj is None:
|
||||||
|
return 0, length
|
||||||
|
elif isinstance(sliceobj, int):
|
||||||
|
return sliceobj, sliceobj + 1
|
||||||
|
elif isinstance(sliceobj, slice):
|
||||||
|
start, end, stride = sliceobj.indices(length)
|
||||||
|
if stride != 1:
|
||||||
|
raise NotImplementedError
|
||||||
|
return start, end
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(sliceobj)
|
||||||
|
|
||||||
|
if not isinstance(key, tuple):
|
||||||
|
yslice = key
|
||||||
|
xslice = None
|
||||||
|
else:
|
||||||
|
yslice, xslice = key
|
||||||
|
|
||||||
|
ystart, yend = indices(yslice, self.height)
|
||||||
|
xstart, xend = indices(xslice, self.width)
|
||||||
|
|
||||||
|
y1 = self.y1 + ystart
|
||||||
|
y2 = self.y1 + yend
|
||||||
|
x1 = self.x1 + xstart
|
||||||
|
x2 = self.x1 + xend
|
||||||
|
return SubImage(self.parent, y1, y2, x1, x2)
|
||||||
|
|
||||||
def _repr_png_(self):
|
def _repr_png_(self):
|
||||||
buf = BytesIO()
|
buf = BytesIO()
|
||||||
imsave(buf, self._data)
|
imsave(buf, self.data)
|
||||||
return buf.getvalue()
|
return buf.getvalue()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def fromfile(cls, filename):
|
def fromfile(cls, filename):
|
||||||
return cls(imread(filename))
|
return cls(imread(filename))
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def space(cls, height, width):
|
|
||||||
return cls(np.ones((height, width)))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def shape(self):
|
def shape(self):
|
||||||
return self._data.shape
|
return self.data.shape
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def T(self):
|
def T(self):
|
||||||
return type(self)(self._data.swapaxes(0, 1))
|
return type(self)(self.data.swapaxes(0, 1))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def height(self):
|
def height(self):
|
||||||
return self._data.shape[0]
|
return self.data.shape[0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def width(self):
|
def width(self):
|
||||||
return self._data.shape[1]
|
return self.data.shape[1]
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def bitmap(self):
|
def bitmap(self):
|
||||||
|
|
@ -76,7 +104,7 @@ class Image(object):
|
||||||
1 = black (letter) pixel
|
1 = black (letter) pixel
|
||||||
"""
|
"""
|
||||||
|
|
||||||
grayscale = rgb2gray(self._data)
|
grayscale = rgb2gray(self.data)
|
||||||
return (grayscale < 1).astype('b')
|
return (grayscale < 1).astype('b')
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
|
@ -123,10 +151,28 @@ class Image(object):
|
||||||
bottom_margin = _get_margin_height(reversed(self.bitmap))
|
bottom_margin = _get_margin_height(reversed(self.bitmap))
|
||||||
return self[top_margin:self.height - bottom_margin, :]
|
return self[top_margin:self.height - bottom_margin, :]
|
||||||
|
|
||||||
def _iter_children(self, min_space):
|
|
||||||
if self.child_cls is None:
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
class SubImage(Image):
|
||||||
|
def __init__(self, parent, y1, y2, x1, x2):
|
||||||
|
self.parent = parent
|
||||||
|
self.y1 = y1
|
||||||
|
self.y2 = y2
|
||||||
|
self.x1 = x1
|
||||||
|
self.x2 = x2
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data(self):
|
||||||
|
return self.parent.data[self.y1:self.y2, self.x1:self.x2]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bitmap(self):
|
||||||
|
return self.parent.bitmap[self.y1:self.y2, self.x1:self.x2]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def T(self):
|
||||||
|
return type(self)(self.parent.T, self.x1, self.x2, self.y1, self.y2)
|
||||||
|
|
||||||
|
def _iter_lines(self, min_space, T=False):
|
||||||
line_start = None
|
line_start = None
|
||||||
prev_line_end = 0
|
prev_line_end = 0
|
||||||
|
|
||||||
|
|
@ -136,28 +182,9 @@ class Image(object):
|
||||||
line_start = i
|
line_start = i
|
||||||
height = line_start - prev_line_end
|
height = line_start - prev_line_end
|
||||||
if height >= min_space:
|
if height >= min_space:
|
||||||
yield self.child_cls.space(height, self.width)
|
yield self[prev_line_end:line_start]
|
||||||
else:
|
else:
|
||||||
if line_start is not None:
|
if line_start is not None:
|
||||||
yield self.child_cls(self._data[line_start:i, :])
|
yield self[line_start:i,:]
|
||||||
line_start = None
|
line_start = None
|
||||||
prev_line_end = i
|
prev_line_end = i
|
||||||
|
|
||||||
|
|
||||||
class Letter(Image):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Line(Image):
|
|
||||||
child_cls = Letter
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
for rotated_letter in self.T._iter_children(min_space=10):
|
|
||||||
yield rotated_letter.T.strip()
|
|
||||||
|
|
||||||
|
|
||||||
class Page(Image):
|
|
||||||
child_cls = Line
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return self._iter_children(min_space=200)
|
|
||||||
|
|
|
||||||
77
pixelocr/page.py
Normal file
77
pixelocr/page.py
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from .image import Image
|
||||||
|
|
||||||
|
|
||||||
|
class PageObject(object):
|
||||||
|
def __init__(self, image):
|
||||||
|
self.image = image
|
||||||
|
|
||||||
|
def _repr_png_(self):
|
||||||
|
return self.image._repr_png_()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def shape(self):
|
||||||
|
return self.image.shape
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
return self.image.width
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self):
|
||||||
|
return self.image.width
|
||||||
|
|
||||||
|
@property
|
||||||
|
def x1(self):
|
||||||
|
return self.image.x1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def x2(self):
|
||||||
|
return self.image.x2
|
||||||
|
|
||||||
|
@property
|
||||||
|
def y1(self):
|
||||||
|
return self.image.y1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def y2(self):
|
||||||
|
return self.image.y2
|
||||||
|
|
||||||
|
@property
|
||||||
|
def x1(self):
|
||||||
|
return self.image.x1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def x2(self):
|
||||||
|
return self.image.x2
|
||||||
|
|
||||||
|
|
||||||
|
class Page(PageObject):
|
||||||
|
def __iter__(self):
|
||||||
|
for line_img in self.image._iter_lines(min_space=200):
|
||||||
|
yield Line(line_img)
|
||||||
|
|
||||||
|
|
||||||
|
class Line(PageObject):
|
||||||
|
def __iter__(self):
|
||||||
|
for rotated_letter_img in self.image.T._iter_lines(min_space=10, T=True):
|
||||||
|
yield Letter(rotated_letter_img.T.strip())
|
||||||
|
|
||||||
|
|
||||||
|
class Letter(PageObject):
|
||||||
|
pass
|
||||||
Loading…
Add table
Add a link
Reference in a new issue