Commit ec4f798d authored by André Anjos's avatar André Anjos 💬

Implement optional pre-cropping stage on preprocessor

parent 2bbaa2db
......@@ -20,8 +20,8 @@ or the attribute ``sub_directory`` in a configuration file loaded **after**
this resource.
"""
from ..preprocessor import Padder, TomesLeeMask, HuangNormalization, NoFilter
from ..preprocessor import Preprocessor
from ..preprocessor import NoCropper, Padder, TomesLeeMask, \
HuangNormalization, NoFilter, Preprocessor
# Filter sizes for the vertical "high-pass" filter
FILTER_HEIGHT = 4
......@@ -32,6 +32,7 @@ PAD_WIDTH = 5
PAD_CONST = 51
preprocessor = Preprocessor(
crop=NoCropper(),
mask=TomesLeeMask(filter_height=FILTER_HEIGHT, filter_width=FILTER_WIDTH),
normalize=HuangNormalization(padding_width=PAD_WIDTH,
padding_constant=PAD_CONST),
......
......@@ -20,8 +20,8 @@ or the attribute ``sub_directory`` in a configuration file loaded **after**
this resource.
"""
from ..preprocessor import Padder, TomesLeeMask, HuangNormalization, NoFilter
from ..preprocessor import Preprocessor
from ..preprocessor import NoCropper, Padder, TomesLeeMask, \
HuangNormalization, NoFilter, Preprocessor
# Filter sizes for the vertical "high-pass" filter
FILTER_HEIGHT = 4
......@@ -32,6 +32,7 @@ PAD_WIDTH = 5
PAD_CONST = 51
preprocessor = Preprocessor(
crop=NoCropper(),
mask=TomesLeeMask(filter_height=FILTER_HEIGHT, filter_width=FILTER_WIDTH),
normalize=HuangNormalization(padding_width=PAD_WIDTH,
padding_constant=PAD_CONST),
......
......@@ -20,8 +20,8 @@ or the attribute ``sub_directory`` in a configuration file loaded **after**
this resource.
"""
from ..preprocessor import Padder, TomesLeeMask, HuangNormalization, NoFilter
from ..preprocessor import Preprocessor
from ..preprocessor import NoCropper, Padder, TomesLeeMask, \
HuangNormalization, NoFilter, Preprocessor
# Filter sizes for the vertical "high-pass" filter
FILTER_HEIGHT = 4
......@@ -32,6 +32,7 @@ PAD_WIDTH = 5
PAD_CONST = 51
preprocessor = Preprocessor(
crop=NoCropper(),
mask=TomesLeeMask(filter_height=FILTER_HEIGHT, filter_width=FILTER_WIDTH),
normalize=HuangNormalization(padding_width=PAD_WIDTH,
padding_constant=PAD_CONST),
......
from .mask import Padder, Masker, NoMask, AnnotatedRoIMask
from .cropper import Cropper, FixedCropper, NoCropper
from .mask import Padder, Masker, FixedMask, AnnotatedRoIMask
from .mask import KonoMask, LeeMask, TomesLeeMask
from .normalize import Normalizer, NoNormalization, HuangNormalization
from .filters import Filter, NoFilter, HistogramEqualization
......@@ -19,9 +20,12 @@ def __appropriate__(*args):
for obj in args: obj.__module__ = __name__
__appropriate__(
Cropper,
FixedCropper,
NoCropper,
Padder,
Masker,
NoMask,
FixedMask,
AnnotatedRoIMask,
KonoMask,
LeeMask,
......
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
'''Base utilities for pre-cropping images'''
import numpy
class Cropper(object):
"""This is the base class for all croppers
It defines the minimum requirements for all derived cropper classes.
"""
def __init__(self):
pass
def __call__(self, image):
"""Overwrite this method to implement your masking method
Parameters:
image (numpy.ndarray): A 2D numpy array of type ``uint8`` with the
input image
Returns:
numpy.ndarray: A 2D numpy array of the same type as the input, with
cropped rows and columns as per request
"""
raise NotImplemented('You must implement the __call__ slot')
class FixedCropper(object):
"""Implements cropping using a fixed suppression of border pixels
The defaults supress no lines from the image and returns an image like the
original.
.. note::
Before choosing values, note you're responsible for knowing what is the
orientation of images fed into this cropper.
Parameters:
top (:py:class:`int`, optional): Number of lines to suppress from the top
of the image. The top of the image corresponds to ``y = 0``.
bottom (:py:class:`int`, optional): Number of lines to suppress from the
bottom of the image. The bottom of the image corresponds to ``y =
height``.
left (:py:class:`int`, optional): Number of lines to suppress from the left
of the image. The left of the image corresponds to ``x = 0``.
right (:py:class:`int`, optional): Number of lines to suppress from the
right of the image. The right of the image corresponds to ``x = width``.
"""
def __init__(self, top=0, bottom=0, left=0, right=0):
self.top = top
self.bottom = bottom
self.left = left
self.right = right
def __call__(self, image):
"""Returns a big mask
Parameters:
image (numpy.ndarray): A 2D numpy array of type ``uint8`` with the
input image
Returns:
numpy.ndarray: A 2D numpy array of type boolean with the caculated
mask. ``True`` values correspond to regions where the finger is
situated
"""
# this should work even if limits are zeros
h, w = image.shape
return image[self.top:h-self.bottom, self.left:w-self.right]
class NoCropper(FixedCropper):
"""Convenience: same as FixedCropper()"""
def __init__(self):
super(NoCropper, self).__init__(0, 0, 0, 0)
......@@ -89,12 +89,41 @@ class Masker(object):
raise NotImplemented('You must implement the __call__ slot')
class NoMask(object):
"""Implements no masking - i.e. returns a mask the same size as input
class FixedMask(object):
"""Implements masking using a fixed suppression of border pixels
The defaults mask no lines from the image and returns a mask of the same size
of the original image where all values are ``True``.
.. note::
Before choosing values, note you're responsible for knowing what is the
orientation of images fed into this masker.
Parameters:
top (:py:class:`int`, optional): Number of lines to suppress from the top
of the image. The top of the image corresponds to ``y = 0``.
bottom (:py:class:`int`, optional): Number of lines to suppress from the
bottom of the image. The bottom of the image corresponds to ``y =
height``.
left (:py:class:`int`, optional): Number of lines to suppress from the left
of the image. The left of the image corresponds to ``x = 0``.
right (:py:class:`int`, optional): Number of lines to suppress from the
right of the image. The right of the image corresponds to ``x = width``.
"""
def __init__(self):
pass
def __init__(self, top=0, bottom=0, left=0, right=0):
self.top = top
self.bottom = bottom
self.left = left
self.right = right
def __call__(self, image):
......@@ -115,7 +144,15 @@ class NoMask(object):
"""
return numpy.ones(image.shape, dtype='bool')
retval = numpy.ones(image.shape, dtype='bool')
# this should work even if limits are zeros
retval[:self.top] = False
retval[-self.bottom:] = False
retval[:,:self.left] = False
retval[:,-self.right:] = False
return retval
class AnnotatedRoIMask(object):
......@@ -428,3 +465,6 @@ class TomesLeeMask(Masker):
else:
w = self.padder.padding_width
return finger_mask[w:-w,w:-w]
......@@ -11,7 +11,8 @@ class Preprocessor (BasePreprocessor):
In this implementation, the finger image is (in this order):
#. The mask is expolated from the image using one of our
#. The image is pre-cropped to remove obvious non-finger image parts
#. The mask is extrapolated from the image using one of our
:py:class:`Masker`'s concrete implementations
#. The image is normalized with one of our :py:class:`Normalizer`'s
#. The image is filtered with one of our :py:class:`Filter`'s
......@@ -19,6 +20,11 @@ class Preprocessor (BasePreprocessor):
Parameters:
crop (:py:class:`Cropper`): An object that will perform pre-cropping on
the input image before a mask can be estimated. It removes parts of the
image which are surely not part of the finger region you'll want to
consider for the next steps.
mask (:py:class:`Masker`): An object representing a Masker instance which
will extrapolate the mask from the input image.
......@@ -34,15 +40,17 @@ class Preprocessor (BasePreprocessor):
"""
def __init__(self, mask, normalize, filter, **kwargs):
def __init__(self, crop, mask, normalize, filter, **kwargs):
BasePreprocessor.__init__(self,
crop = crop,
mask = mask,
normalize = normalize,
filter = filter,
**kwargs
)
self.crop = crop
self.mask = mask
self.normalize = normalize
self.filter = filter
......@@ -66,7 +74,8 @@ class Preprocessor (BasePreprocessor):
"""
mask = self.mask(data)
cropped = self.crop(data)
mask = self.mask(cropped)
data, mask = self.normalize(data, mask)
data = self.filter(data, mask)
return data, mask
......
......@@ -42,10 +42,11 @@ def test_finger_crop():
img = bob.io.base.load(input_filename)
from bob.bio.vein.preprocessor import Preprocessor, LeeMask, \
from bob.bio.vein.preprocessor import Preprocessor, NoCropper, LeeMask, \
HuangNormalization, NoFilter
processor = Preprocessor(
NoCropper(),
LeeMask(filter_height=40, filter_width=4),
HuangNormalization(padding_width=0, padding_constant=0),
NoFilter(),
......@@ -112,9 +113,10 @@ def test_max_curvature_HE():
input_img = bob.io.base.load(input_img_filename)
# Preprocess the data and apply Histogram Equalization postprocessing (same parameters as in maximum_curvature.py configuration file + postprocessing)
from bob.bio.vein.preprocessor import Preprocessor, LeeMask, \
from bob.bio.vein.preprocessor import Preprocessor, NoCropper, LeeMask, \
HuangNormalization, HistogramEqualization
processor = Preprocessor(
NoCropper(),
LeeMask(filter_height=40, filter_width=4),
HuangNormalization(padding_width=0, padding_constant=0),
HistogramEqualization(),
......@@ -161,9 +163,10 @@ def test_repeated_line_tracking_HE():
input_img = bob.io.base.load(input_img_filename)
# Preprocess the data and apply Histogram Equalization postprocessing (same parameters as in repeated_line_tracking.py configuration file + postprocessing)
from bob.bio.vein.preprocessor import Preprocessor, LeeMask, \
from bob.bio.vein.preprocessor import Preprocessor, NoCropper, LeeMask, \
HuangNormalization, HistogramEqualization
processor = Preprocessor(
NoCropper(),
LeeMask(filter_height=40, filter_width=4),
HuangNormalization(padding_width=0, padding_constant=0),
HistogramEqualization(),
......@@ -214,9 +217,10 @@ def test_wide_line_detector_HE():
input_img = bob.io.base.load(input_img_filename)
# Preprocess the data and apply Histogram Equalization postprocessing (same parameters as in wide_line_detector.py configuration file + postprocessing)
from bob.bio.vein.preprocessor import Preprocessor, LeeMask, \
from bob.bio.vein.preprocessor import Preprocessor, NoCropper, LeeMask, \
HuangNormalization, HistogramEqualization
processor = Preprocessor(
NoCropper(),
LeeMask(filter_height=40, filter_width=4),
HuangNormalization(padding_width=0, padding_constant=0),
HistogramEqualization(),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment