Source code for genalog.degradation.degrader

# ---------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
# ---------------------------------------------------------

import copy
import inspect
from enum import Enum

from genalog.degradation import effect

DEFAULT_METHOD_PARAM_TO_INCLUDE = "src"


[docs]class ImageState(Enum): ORIGINAL_STATE = "ORIGINAL_STATE" CURRENT_STATE = "CURRENT_STATE"
[docs]class Degrader: """ An object for applying multiple degradation effects onto an image""" def __init__(self, effects): """ Arguments: effects (list) : a list of 2-element tuple (method_name, method_kwargs) where: :method_name: the name of the degradation method (method must be defined in 'genalog.degradation.effect') :method_kwargs: the keyword arguments of the corresponding method Example: :: [ ("blur", {"radius": 3}), ("bleed_through", {"alpha": 0.8), ("morphology", {"operation": "open", "kernel_shape": (3,3), "kernel_type": "ones"}) ] The example above will apply degradation effects to the images in the following sequence: :: "blur" -> "bleed_through" -> "morphological operation (open)" """ Degrader.validate_effects(effects) self.effects_to_apply = copy.deepcopy(effects) self._add_default_method_param()
[docs] @staticmethod def validate_effects(effects): """Validate the effects list Arguments: effects (list) : a list of 2-element tuple ``(method_name, method_kwargs)`` that defines: 1. ``method_name`` : the name of the degradation method \ (method must be defined in ``genalog.degradation.effect``) 2. ``method_kwargs`` : the keyword arguments of the corresponding method Example: :: [ ("blur", {"radius": "3"}), ("bleed_through", {"alpha":"0.8"}), ("morphology", {"operation": "open", "kernel_shape": (3,3), "kernel_type": "ones"}), ] Raises: ValueError: raise this error when: ``method_name`` not defined in "genalog.degradation.effect" ``method_kwargs`` is not a valid keyword arguments in the corresponding method """ for effect_tuple in effects: method_name, method_kwargs = effect_tuple try: # Try to find corresponding degradation method in the module method = getattr(effect, method_name) except AttributeError: raise ValueError( f"Method '{method_name}' is not defined in 'genalog.degradation.effect'" ) # Get the method signatures method_sign = inspect.signature(method) # Check if method parameters are valid for ( param_name ) in method_kwargs.keys(): # i.e. ["operation", "kernel_shape", ...] if param_name not in method_sign.parameters: method_args = [param for param in method_sign.parameters] raise ValueError( f"Invalid parameter name '{param_name}' for method 'genalog.degradation.effect.{method_name}()'. " + f"Method parameter names are: {method_args}" )
def _add_default_method_param(self): """All methods in "genalog.degradation.effect" module have a required method parameter named "src". This parameter will be included if not provided by the input keyword argument dictionary. """ for effect_tuple in self.effects_to_apply: method_name, method_kwargs = effect_tuple if DEFAULT_METHOD_PARAM_TO_INCLUDE not in method_kwargs: method_kwargs[ DEFAULT_METHOD_PARAM_TO_INCLUDE ] = ImageState.CURRENT_STATE
[docs] def apply_effects(self, src): """Apply degradation effects in sequence Arguments: src (numpy.ndarray) : source image of shape (rows, cols) Returns: a copy of the source image {numpy.ndarray} after apply the effects """ self.original_state = src self.current_state = src # Preserve the original effect instructions effects_to_apply = copy.deepcopy(self.effects_to_apply) for effect_tuple in effects_to_apply: method_name, method_kwargs = effect_tuple method = getattr(effect, method_name) # Replace constants (i.e. ImageState.ORIGINAL_STATE) with actual image state method_kwargs = self.insert_image_state(method_kwargs) # Calling the degradation method self.current_state = method(**method_kwargs) return self.current_state
[docs] def insert_image_state(self, kwargs): """Replace the enumeration (ImageState) with the actual image in the keyword argument dictionary Arguments: kwargs (dict) : keyword argument dictionary Ex: {"src": ImageState.ORIGINAL_STATE, "radius": 5} Returns: return keyword argument dictionary replaced with reference to the image """ for keyword, argument in kwargs.items(): if argument is ImageState.ORIGINAL_STATE: kwargs[keyword] = self.original_state.copy() if argument is ImageState.CURRENT_STATE: kwargs[keyword] = self.current_state.copy() return kwargs