simple-imaging
This is the place where you can find information about how to use the methods as well as examples of application.
simple-imaging was developed during the Digital Imaging Processing course, and as such should not be considered producion capable yet.
New features and improvements are on the way.
File reading and writing
For the reading and writing of files two utility functions have been created.
There are also functions to deal with RGB channel splitting and merging.
- simple_imaging.image.extract_channels(img: Image) list[Image, Image, Image]
Extracts the RGB channels from a P3 image
- Args:
img (Image): a P3 Image
- Returns:
list[Image, Image, Image]: a list where each element is a channel in the RGB Image
- simple_imaging.image.merge_channels(channels: list[Image, Image, Image]) Image
Merges 3 P2 images into one RGB image
- Args:
channels (list[Image, Image, Image]): input images, each corresponding to a channel in the RGB model
- Returns:
Image: a composite P3 Image
- simple_imaging.image.read_file(filepath: str) simple_imaging.image.Image
File reading utility
Given a file path, attempts to validade file contents, if said contents are valid, returns an Image object
- Args:
filepath {str} – path for desired Netpbm file
- Returns:
Image – Image object generated by the file contents
- simple_imaging.image.save_file(filepath: str, image: simple_imaging.image.Image) None
Writes image to disk
- Args:
filepath (str): the path to write the file too
image (Image): an Image object to be written
- simple_imaging.image.validate_image_compatibility(image1: simple_imaging.image.Image, image2: simple_imaging.image.Image) bool
Validates the compatibility between two images
- Returns:
bool: True if the images are compatible
Image class
This is where the processing operations are contained. Most of said methods accept the inplace argument, a boolean that controls if the result should be generated as a new Image instance or if the operation should modify the current values.
The contents of the image are represented as a list[list[Pixel]], where Pixel is an abstraction for the Grayscale and RGB case. This allows for future extending of those custom types (like the RGBA, and RGB with alpha channel, for example).
- class simple_imaging.image.Image(header: str, max_level: int, dimensions: tuple[int, int], contents: list[list[Pixel]] = None)
- __init__(header: str, max_level: int, dimensions: tuple[int, int], contents: list[list[Pixel]] = None)
Image class
- Args:
header (str): A string of the image header, accepts (P1, P2 and P3)
max_level (int): Max number of gray levels allowed for the image
dimensions (tuple[int, int]): The (width, height) dimensions of the image
contents (list[list[Pixel]], optional): A Pixel matrix to pre-populate the iamge. Defaults to None.
- Raises:
ValidationError: If there’re invalid dimensions (below 0, None)
- _generate_working_copy(populate: bool = False) list[list[Pixel]]
Genertes a pixel matrix in the current image dimentions for processing
- Args:
populate (bool, optional): If true will populate the matrix with the current values. Defaults to False.
- Returns:
list[list[Pixel]]: a X * Y matrix of pixels
- _kernel_filter(kernel: str = 'laplace', inplace: bool = True) simple_imaging.image.Image
Abstract kernel filtering method
given a selection of predefined kernels, this method will apply that kernel to the image.
- Current predefined options are:
identity
edge
laplace
laplace2
box_blur
gaussian_blur
sharpen
emboss
- Args:
kernel (str, optional): The kernel to be utilized. Defaults to “laplace”.
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Raises:
ValidationError: if the passed kernel is not defined.
- Returns:
Image: processing result
- _return_result(pixel_matrix: list[list[Pixel]], inplace: bool = True) Image
Utility method to handle the return of the processing result
- Args:
pixel_matrix (list[list[Pixel]]): the processed pixel matrix
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- _sliding_window(size: int) Generator[list[list[int]], None, None]
Utility method for sliding window operations
This method will slide a size x size window in the current matrix, returning the current window in each step of the generator.
This method uses the “extending” policy meaning that the border pixels are virtually repeated for this process
- Args:
size (int): the size of the sliding window
- Yields:
Generator[list[list[int]], None, None]: a generator object that yields the current window
- add_image(other_image: simple_imaging.image.Image, inplace: bool = True) simple_imaging.image.Image
Image addition
Given two compatible images, realizes the addition of each corresponding pixel
- Args:
other_image (Image): image to be added
inplace (bool, optional): If False will generate a new image as result. Defaults to True.
- Raises:
ImcompatibleImages: If the images are incompatible (mismatching dimensions or headers)
- Returns:
Image: processing result
- average_filter(kernel: int, inplace: bool = True) simple_imaging.image.Image
Average filtering
Given a kernel size this method will get the arithmetic average of the pixels in a sliding window and apply the result to the pivot (central) pixel.
- Args:
kernel (int): kernel size. a kernel of 3 will result in a sliding window of 3x3 pixels.
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- binarization(threshold: int, inplace: bool = True) simple_imaging.image.Image
Binarization process
Given a threshold (0 < threshold < 255), this operation wil set pixels below it to black and above it to white.
- Args:
threshold (int): the level to split into white and black pixels
inplace (bool, optional): Flag to set the opreationa s inplace. Defaults to True.
- Returns:
Image: resulting process
- copy_current_image() simple_imaging.image.Image
Creates a deepcopy of the current image
- Returns:
Image: copy (full copy) of the current image data
- darken(level: int, inplace: bool = True) simple_imaging.image.Image
Darken image method
Given a level in pixel value, this will darken the image by that much. The value must obey the criteria (0<=level<=255), else an Exception is raised
- Arguments:
level {int} – Pixel value (as in how much) for image enlightening.
inplace (bool, optional): If the operation should be executed in place. Defaults to True.
- Returns:
- Image: Resulting Image object from operation,
returns a copy if inplace is False
- classmethod from_file(filepath: str) simple_imaging.image.Image
Creates image from file
- Args:
filepath (str): path to source file
- gamma_transformation(gamma: float, c: int | float = 1, inplace: bool = True) Image
Gamma transformation
Applies the gamma transformations processing in the image. Uses the formula c * p ^ gamma, where p is the current pixel value.
- Args:
gamma (float): gamma value
c (Union[int, float], optional): Adjustment constant. Defaults to 1.
inplace (bool, optional): If the transformations should be inplace. Defaults to True.
- Returns:
Image: [description]
- get_histogram(pixel_data: list[list[Pixel]] = None) dict[str, int]
Generates the histogram for the image
- Args:
pixel_data (list[list[Pixel]], optional): the pixel matrix to work on. Defaults to None. If None passed, will use the complete current image data.
- Raises:
ValidationError: In case he image is not grayscale
- Returns:value
dict[str, int]: histogram for image as a dictionary, where each key is the pixel value and each value is the number of courrences in the image
- get_pixel(x: int, y: int) simple_imaging.types.Pixel
gets the pixel in a certain location
- Args:
x (int): x position
y (int): y position
- Raises:
ValidationError: if the location is outside current image bounds.
- Returns:
Pixel: the Pixel object at the desired location
- high_boost_filter(k: int | float = 1, inplace: bool = True) Image
Applies the High-Boost filter
- Args:
k (int, optional): adjustment constant. Defaults to 1.
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- highlight_band(threshold: tuple[int, int], intensity: int, intensity_outside: int | None = None, inplace: bool = True) Image
Highlights an interval of pixels
- Args:
threshold (tuple[int, int]): the interval of values to highlight, must obey (a < b) criteria.
intensity (int): the value to set those pixels that are inside the threshold.
intensity_outside (int, optional): the value to set pixels outside the threshold. Defaults to None.
inplace (bool, optional): Controls the generation of a new image as result. Defaults to True.
- Raises:
ValidationError: In case the threshold does not obey the criteria
- Returns:
Image: the result of the processing
- histogram_equalization(inplace: bool = True) simple_imaging.image.Image
Does the global histogram equalization
- Args:
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- horizontal_mirror(inplace: bool = True) simple_imaging.image.Image
Horizontal Mirroring operation
- Args:
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- laplacian_filter(inplace: bool = True) simple_imaging.image.Image
Applies the laplacian filter to the image
- Args:
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- lighten(level: int, inplace: bool = True) simple_imaging.image.Image
Lighten image method
Given a level in pixel value, this will enlighten the image by that much. The value must obey the criteria (0<=level<=255), else an Exception is raised
- Arguments:
level {int} – Pixel value (as in how much) for image enlightening
inplace (bool, optional): If the operation should be executed in place. Defaults to True.
- Returns:
- Image: Resulting Image object from operation,
returns a copy if inplace is False
- local_histogram_equalization(kernel: int, inplace: bool = True) simple_imaging.image.Image
Local histogram euqalization
- Args:
kernel (int): size of the window for the LHE process.
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- median_filter(kernel: int, inplace: bool = True) simple_imaging.image.Image
Median filtering
Given a kernel size this method will get the median of the ordered list of pixels in a sliding window and apply the result to the pivot (central) pixel.
- Args:
kernel (int): kernel size. a kernel of 3 will result in a sliding window of 3x3 pixels.
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- multiply_image(value: int, inplace: bool = True) simple_imaging.image.Image
Image multiplication by an integer
Given an integer value, realizes the pixel-wise multiplication of the value
- Args:
value (int): integer to multiply the image by
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- negative(inplace: bool = True) simple_imaging.image.Image
Negative operation
For each pixel in the image, invokes the Pixel negative method
- Args:
inplace (bool, optional): Controls if the result will be a new Image. Defaults to True.
- Returns:
Image: Processing result
- rotate_180(inplace: bool = True) simple_imaging.image.Image
180 deegres rotation
- Args:
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- rotate_90(clockwise: bool = True, inplace: bool = True) simple_imaging.image.Image
90 degree rotation
- Args:
clockwise (bool, optional): defines the direction of rotation. Defaults to True.
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
- set_pixel(x: int, y: int, pixel: simple_imaging.types.Pixel) None
Sets a pixel to a location
- Args:
x (int): x position
y (int): y position
pixel (Pixel): pixel to replace the contents of that position
- Raises:
ValidationError: if the location is outside the bound of the current image
- subtract_image(other_image: simple_imaging.image.Image, inplace: bool = True) simple_imaging.image.Image
Image subtraction
Given two compatible images, realizes the subtraction of each corresponding pixel
- Args:
other_image (Image): image to be subtracted
inplace (bool, optional): If False will generate a new image as result. Defaults to True.
- Raises:
ImcompatibleImages: If the images are incompatible (mismatching dimensions or headers)
- Returns:
Image: processing result
- vertical_mirror(inplace: bool = True) simple_imaging.image.Image
Vertical mirroring operation
- Args:
inplace (bool, optional): If false will generate a new image as result. Defaults to True.
- Returns:
Image: processing result
Custom Types
For this project we defined a base abstract Pixel class using Python’s Protocol.
This allowed for the definition of abstract basic pixel operations (like, darken, lighten and negative) and ensuring that there’s no heavy couplling between Image and the Pixel type
- class simple_imaging.image.Pixel(*args, **kwargs)
Abstract Pixel class
This class holds the abstractions to the pixel operation methods
- class simple_imaging.types.GrayPixel(value: int = 0)
- __init__(value: int = 0)
Grayscale Pixel
- Args:
value (int, optional): value for this pixel. Defaults to 0.
- darken(level: int) None
Darkens the current pixel
- Args:
level (int): amount to subtract from current value
- lighten(level: int) None
lightens the current pixel
- Args:
level (int): amount to add to current value
- negative() None
Negative operation
Sets the pixel value to 255-current_value obeying the 0~255 interval
Utilities
There’re many utility functions used to parse, validate and process the input file before the image operations. They are documented below.
- simple_imaging.utils._convert_into_tuples(value_list: List[int]) List[Tuple[int, int, int]]
- simple_imaging.utils._extract_dimensions(file_contents: List[str]) Tuple[int, int, List[int]]
- simple_imaging.utils._extract_first_element(file_contents: List[simple_imaging.utils.T]) Tuple[simple_imaging.utils.T, List[simple_imaging.utils.T]]
- simple_imaging.utils._extract_header(file_contents: List[str]) Tuple[str, List[str]]
- simple_imaging.utils._extract_max_level(value_data: List[simple_imaging.utils.Pixel]) Tuple[simple_imaging.utils.Pixel, List[simple_imaging.utils.Pixel]]
- simple_imaging.utils._format_pixel_data(data: List[simple_imaging.utils.T], m: int) List[List[simple_imaging.utils.T]]
- simple_imaging.utils._generate_pixel_matrix_grayscale(pixel_data: List[List[int]], x: int, y: int) List[List[simple_imaging.types.GrayPixel]]
- simple_imaging.utils._generate_pixel_matrix_rgb(pixel_data: List[List[Tuple[int, int, int]]], x: int, y: int) List[List[simple_imaging.types.RGBPixel]]
- simple_imaging.utils._parse_value_data_grayscale(value_data: List[int], x: int, y: int)
- simple_imaging.utils._parse_value_data_rgb(value_data: List[Tuple[int, int, int]], x: int, y: int)
- simple_imaging.utils._validate_data_length(data_length: int, desired_length: int) bool
- simple_imaging.utils._validate_max_value(max_value: simple_imaging.utils.Pixel) bool
- simple_imaging.utils.get_split_strings(file_contents: TextIO) List[str]
Utility function to read file contents
Given a filepath as string, this function will read it’s contents and split out the values by newlines and spaces. Returns a non-agnostic representation of its contents as a list of strings
- Arguments:
filepath {str} – path to the desired file for processing
- Returns:
List[str] – representation of file contents as a list of strings.
- simple_imaging.utils.parse_file_contents(file_contents: List[str]) Dict[str, Any]
Utility function to validate and parse file contents
Given the file contents as a list of strings, validates the data and raises any errors. If no problems occur, returns the parsed data as a dictionary.
- Args:
file_contents (List[str]): File contents as a list of strings
- Raises:
InvalidConfigsError: If the provide file has incorrect data (non matching pixels, for example) InvalidFileError: The provide file has invalid data (special characters for example)
- Returns:
Dict[str, Any]: [description]
Exceptions
A set of custom Exceptions has been screated to allow for more specific errors when dealing with the validations.
- exception simple_imaging.errors.ImcompatibleImages
Exception for cases where there’s attempt to operate in 2 images and they are incompatible
- exception simple_imaging.errors.InvalidConfigsError
Exception for situation where the file passed as input is not valid
- E.g.:
non-matching pixel amount
special characters
missing values (for width, height, etc)
- exception simple_imaging.errors.InvalidFileError
Exception for cases where the criteria for a certain operation or value is not met
- exception simple_imaging.errors.InvalidHeaderError
Exception for cases where and unknow header if passed or and invalid header for a certain operation is used
- exception simple_imaging.errors.UnkownError
Exception for any case where there’s no clear cause for a crash
- exception simple_imaging.errors.ValidationError
Exception for cases where the criteria for a certain operation or value is not met