diff --git a/bob/bio/face/preprocessor/Base.py b/bob/bio/face/preprocessor/Base.py index 0e296e423f547daf987377aa1e3168fe2396a36d..3170b408733f8e92081782fd5487b5f7c40ac826 100644 --- a/bob/bio/face/preprocessor/Base.py +++ b/bob/bio/face/preprocessor/Base.py @@ -1,27 +1,59 @@ -import numpy import bob.io.image import bob.ip.color +import numpy +from sklearn.base import BaseEstimator +from sklearn.base import TransformerMixin + + +def change_color_channel(image, color_channel): + if image.ndim == 2: + if color_channel == "rgb": + return bob.ip.color.gray_to_rgb(image) + if color_channel != "gray": + raise ValueError( + "There is no rule to extract a " + + color_channel + + " image from a gray level image!" + ) + return image -from sklearn.base import TransformerMixin, BaseEstimator + if color_channel == "rgb": + return image + if color_channel == "gray": + return bob.ip.color.rgb_to_gray(image) + if color_channel == "red": + return image[0, :, :] + if color_channel == "green": + return image[1, :, :] + if color_channel == "blue": + return image[2, :, :] + + raise ValueError( + "The image channel '%s' is not known or not yet implemented", color_channel + ) class Base(TransformerMixin, BaseEstimator): """Performs color space adaptations and data type corrections for the given - image. + image. - **Parameters:** + **Parameters:** - dtype : :py:class:`numpy.dtype` or convertible or ``None`` - The data type that the resulting image will have. + dtype : :py:class:`numpy.dtype` or convertible or ``None`` + The data type that the resulting image will have. - color_channel : one of ``('gray', 'red', 'gren', 'blue', 'rgb')`` - The specific color channel, which should be extracted from the image. - """ + color_channel : one of ``('gray', 'red', 'gren', 'blue', 'rgb')`` + The specific color channel, which should be extracted from the image. + """ def __init__(self, dtype=None, color_channel="gray", **kwargs): - self.channel = color_channel + self.color_channel = color_channel self.dtype = dtype + @property + def channel(self): + return self.color_channel + def _more_tags(self): return {"stateless": True, "requires_fit": False} @@ -31,85 +63,62 @@ class Base(TransformerMixin, BaseEstimator): def color_channel(self, image): """color_channel(image) -> channel - Returns the channel of the given image, which was selected in the - constructor. Currently, gray, red, green and blue channels are supported. + Returns the channel of the given image, which was selected in the + constructor. Currently, gray, red, green and blue channels are supported. - **Parameters:** + **Parameters:** - image : 2D or 3D :py:class:`numpy.ndarray` - The image to get the specified channel from. + image : 2D or 3D :py:class:`numpy.ndarray` + The image to get the specified channel from. - **Returns:** + **Returns:** - channel : 2D or 3D :py:class:`numpy.ndarray` - The extracted color channel. - """ + channel : 2D or 3D :py:class:`numpy.ndarray` + The extracted color channel. + """ - if image.ndim == 2: - if self.channel == "rgb": - return bob.ip.color.gray_to_rgb(image) - if self.channel != "gray": - raise ValueError( - "There is no rule to extract a " - + self.channel - + " image from a gray level image!" - ) - return image - - if self.channel == "rgb": - return image - if self.channel == "gray": - return bob.ip.color.rgb_to_gray(image) - if self.channel == "red": - return image[0, :, :] - if self.channel == "green": - return image[1, :, :] - if self.channel == "blue": - return image[2, :, :] - - raise ValueError( - "The image channel '%s' is not known or not yet implemented", self.channel - ) + return change_color_channel(image, self.color_channel) def data_type(self, image): """data_type(image) -> image - Converts the given image into the data type specified in the constructor of - this class. If no data type was specified, or the ``image`` is ``None``, no - conversion is performed. + Converts the given image into the data type specified in the constructor of + this class. If no data type was specified, or the ``image`` is ``None``, no + conversion is performed. - **Parameters:** + **Parameters:** - image : 2D or 3D :py:class:`numpy.ndarray` - The image to convert. + image : 2D or 3D :py:class:`numpy.ndarray` + The image to convert. - **Returns:** + **Returns:** - image : 2D or 3D :py:class:`numpy.ndarray` - The image converted to the desired data type, if any. - """ + image : 2D or 3D :py:class:`numpy.ndarray` + The image converted to the desired data type, if any. + """ if self.dtype is not None and image is not None: image = image.astype(self.dtype) return image - def transform(self, image, annotations=None): - """__call__(image, annotations = None) -> image + def transform(self, images, annotations=None): + """Extracts the desired color channel and converts to the desired data type. - Extracts the desired color channel and converts to the desired data type. + **Parameters:** - **Parameters:** + image : 2D or 3D :py:class:`numpy.ndarray` + The image to preprocess. - image : 2D or 3D :py:class:`numpy.ndarray` - The image to preprocess. + annotations : any + Ignored. - annotations : any - Ignored. + **Returns:** - **Returns:** + image : 2D :py:class:`numpy.ndarray` + The image converted converted to the desired color channel and type. + """ + return [self._transform_one_image(img) for img in images] - image : 2D :py:class:`numpy.ndarray` - The image converted converted to the desired color channel and type. - """ + def _transform_one_image(self, image): assert isinstance(image, numpy.ndarray) and image.ndim in (2, 3) # convert to grayscale image = self.color_channel(image) diff --git a/bob/bio/face/preprocessor/utils.py b/bob/bio/face/preprocessor/utils.py index ffd5602632cb909a465d2238a3f58e0b74325e0c..d59c9bd85e8b1c961df11e65909f5515f5ed48c0 100644 --- a/bob/bio/face/preprocessor/utils.py +++ b/bob/bio/face/preprocessor/utils.py @@ -1,5 +1,4 @@ import bob.bio.base -import six def load_cropper(face_cropper): @@ -7,25 +6,9 @@ def load_cropper(face_cropper): if face_cropper is None: cropper = None - elif isinstance(face_cropper, six.string_types): + elif isinstance(face_cropper, str): cropper = bob.bio.base.load_resource(face_cropper, "preprocessor") else: cropper = face_cropper return cropper - - -def load_cropper_only(face_cropper): - from .FaceCrop import FaceCrop - - if face_cropper is None: - cropper = None - elif isinstance(face_cropper, six.string_types): - cropper = bob.bio.base.load_resource(face_cropper, "preprocessor") - elif isinstance(face_cropper, FaceCrop): - cropper = face_cropper - else: - raise ValueError("The given face cropper type is not understood") - - assert cropper is None or isinstance(cropper, FaceCrop) - return cropper