Return gray image from rgb image  rgbtograynp.array127, 255, 0 array187.6453  rgbtograynp.array0, 0, 0 array0.  rgbtograynp.array2, 4, 1 array3.0598  rgbtograynp.array26, 255, 14, 5, 147, 20, 1, 200, 0 array159.0524,  90.0635, 117.6989 Return binary image from gray image  graytobinarynp.array127, 255, 0 arrayFalse,  True, False  graytobinarynp.array0 arrayFalse  graytobinarynp.array26.2409, 4.9315, 1.4729 arrayFalse, False, False  graytobinarynp.array26, 255, 14, 5, 147, 20, 1, 200, 0 arrayFalse,  True, False, False,  True, False, False,  True, False Return dilated image  dilationnp.arrayTrue, False, True, np.array0, 1, 0 arrayFalse, False, False  dilationnp.arrayFalse, False, True, np.array1, 0, 1 arrayFalse, False, False Copy image to padded image Iterate over image  apply kernel read original image kernel to be applied Save the output image
from pathlib import Path

import numpy as np
from PIL import Image


def rgb_to_gray(rgb: np.ndarray) -> np.ndarray:
    """
    Return gray image from rgb image
    >>> rgb_to_gray(np.array([[[127, 255, 0]]]))
    array([[187.6453]])
    >>> rgb_to_gray(np.array([[[0, 0, 0]]]))
    array([[0.]])
    >>> rgb_to_gray(np.array([[[2, 4, 1]]]))
    array([[3.0598]])
    >>> rgb_to_gray(np.array([[[26, 255, 14], [5, 147, 20], [1, 200, 0]]]))
    array([[159.0524,  90.0635, 117.6989]])
    """
    r, g, b = rgb[:, :, 0], rgb[:, :, 1], rgb[:, :, 2]
    return 0.2989 * r + 0.5870 * g + 0.1140 * b


def gray_to_binary(gray: np.ndarray) -> np.ndarray:
    """
    Return binary image from gray image
    >>> gray_to_binary(np.array([[127, 255, 0]]))
    array([[False,  True, False]])
    >>> gray_to_binary(np.array([[0]]))
    array([[False]])
    >>> gray_to_binary(np.array([[26.2409, 4.9315, 1.4729]]))
    array([[False, False, False]])
    >>> gray_to_binary(np.array([[26, 255, 14], [5, 147, 20], [1, 200, 0]]))
    array([[False,  True, False],
           [False,  True, False],
           [False,  True, False]])
    """
    return (gray > 127) & (gray <= 255)


def dilation(image: np.ndarray, kernel: np.ndarray) -> np.ndarray:
    """
    Return dilated image
    >>> dilation(np.array([[True, False, True]]), np.array([[0, 1, 0]]))
    array([[False, False, False]])
    >>> dilation(np.array([[False, False, True]]), np.array([[1, 0, 1]]))
    array([[False, False, False]])
    """
    output = np.zeros_like(image)
    image_padded = np.zeros(
        (image.shape[0] + kernel.shape[0] - 1, image.shape[1] + kernel.shape[1] - 1)
    )

    # Copy image to padded image
    image_padded[kernel.shape[0] - 2 : -1 :, kernel.shape[1] - 2 : -1 :] = image

    # Iterate over image & apply kernel
    for x in range(image.shape[1]):
        for y in range(image.shape[0]):
            summation = (
                kernel * image_padded[y : y + kernel.shape[0], x : x + kernel.shape[1]]
            ).sum()
            output[y, x] = int(summation > 0)
    return output


if __name__ == "__main__":
    # read original image
    lena_path = Path(__file__).resolve().parent / "image_data" / "lena.jpg"
    lena = np.array(Image.open(lena_path))
    # kernel to be applied
    structuring_element = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
    output = dilation(gray_to_binary(rgb_to_gray(lena)), structuring_element)
    # Save the output image
    pil_img = Image.fromarray(output).convert("RGB")
    pil_img.save("result_dilation.png")
