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

class simple_imaging.types.Pixel(*args, **kwargs)

Abstract Pixel class

This class holds the abstractions to the pixel operation methods

__init__(*args, **kwargs)
class simple_imaging.types.RGBPixel(*args, **kwds)
__init__(red: int = 0, green: int = 0, blue: int = 0) None

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

Indices and tables