diff --git a/digital_image_processing/resize/__init__.py b/digital_image_processing/resize/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/digital_image_processing/resize/resize.py b/digital_image_processing/resize/resize.py new file mode 100644 index 000000000..b7d493e70 --- /dev/null +++ b/digital_image_processing/resize/resize.py @@ -0,0 +1,69 @@ +""" Multiple image resizing techniques """ +import numpy as np +from cv2 import imread, imshow, waitKey, destroyAllWindows + + +class NearestNeighbour: + """ + Simplest and fastest version of image resizing. + Source: https://en.wikipedia.org/wiki/Nearest-neighbor_interpolation + """ + + def __init__(self, img, dst_width: int, dst_height: int): + if dst_width < 0 or dst_height < 0: + raise ValueError(f"Destination width/height should be > 0") + + self.img = img + self.src_w = img.shape[1] + self.src_h = img.shape[0] + self.dst_w = dst_width + self.dst_h = dst_height + + self.ratio_x = self.src_w / self.dst_w + self.ratio_y = self.src_h / self.dst_h + + self.output = self.output_img = ( + np.ones((self.dst_h, self.dst_w, 3), np.uint8) * 255 + ) + + def process(self): + for i in range(self.dst_h): + for j in range(self.dst_w): + self.output[i][j] = self.img[self.get_y(i)][self.get_x(j)] + + def get_x(self, x: int) -> int: + """ + Get parent X coordinate for destination X + :param x: Destination X coordinate + :return: Parent X coordinate based on `x ratio` + >>> nn = NearestNeighbour(imread("digital_image_processing/image_data/lena.jpg", 1), 100, 100) + >>> nn.ratio_x = 0.5 + >>> nn.get_x(4) + 2 + """ + return int(self.ratio_x * x) + + def get_y(self, y: int) -> int: + """ + Get parent Y coordinate for destination Y + :param y: Destination X coordinate + :return: Parent X coordinate based on `y ratio` + >>> nn = NearestNeighbour(imread("digital_image_processing/image_data/lena.jpg", 1), 100, 100) + >>> nn.ratio_y = 0.5 + >>> nn.get_y(4) + 2 + """ + return int(self.ratio_y * y) + + +if __name__ == "__main__": + dst_w, dst_h = 800, 600 + im = imread("image_data/lena.jpg", 1) + n = NearestNeighbour(im, dst_w, dst_h) + n.process() + + imshow( + f"Image resized from: {im.shape[1]}x{im.shape[0]} to {dst_w}x{dst_h}", n.output + ) + waitKey(0) + destroyAllWindows() diff --git a/digital_image_processing/test_digital_image_processing.py b/digital_image_processing/test_digital_image_processing.py index 89cf6007a..327e2c67f 100644 --- a/digital_image_processing/test_digital_image_processing.py +++ b/digital_image_processing/test_digital_image_processing.py @@ -11,6 +11,7 @@ import digital_image_processing.change_contrast as cc import digital_image_processing.convert_to_negative as cn import digital_image_processing.sepia as sp import digital_image_processing.dithering.burkes as bs +import digital_image_processing.resize.resize as rs from cv2 import imread, cvtColor, COLOR_BGR2GRAY from numpy import array, uint8 from PIL import Image @@ -82,3 +83,10 @@ def test_burkes(file_path: str = "digital_image_processing/image_data/lena_small burkes = bs.Burkes(imread(file_path, 1), 120) burkes.process() assert burkes.output_img.any() + +def test_nearest_neighbour( + file_path: str = "digital_image_processing/image_data/lena_small.jpg", +): + nn = rs.NearestNeighbour(imread(file_path, 1), 400, 200) + nn.process() + assert nn.output.any()