From 946580320a7b404d56a66e5ad4f412ab95309d9c Mon Sep 17 00:00:00 2001 From: 0x01FE Date: Wed, 11 Sep 2024 14:42:56 -0500 Subject: [PATCH] put the filters in a seperate file --- filters.py | 71 ++++++++++++++++++++++++++ sobel.py | 146 +++++------------------------------------------------ 2 files changed, 84 insertions(+), 133 deletions(-) create mode 100644 filters.py diff --git a/filters.py b/filters.py new file mode 100644 index 0000000..5fca603 --- /dev/null +++ b/filters.py @@ -0,0 +1,71 @@ +import logging + +from PIL import Image, ImageFilter +import scipy.signal +import numpy as np + +logging.getLogger(__name__) + +sobel_x_kernel = np.array(( + (1, 0, -1), + (2, 0, -2), + (1, 0, -1) +)) + +sobel_y_kernel = np.transpose(sobel_x_kernel) + +def difference_of_gaussians(img: Image.Image, blur_strength_1: float | None = 1.0, blur_strength_2: float | None = 1.2) -> Image.Image: + blur_1 = img.filter(ImageFilter.GaussianBlur(blur_strength_1)) + blur_2 = img.filter(ImageFilter.GaussianBlur(blur_strength_2)) + + w, h = img.size + + dog = Image.new(img.mode, img.size) + + for pixel_y in range(h): + for pixel_x in range(w): + + coords = (pixel_x, pixel_y) + + p1 = blur_1.getpixel(coords) + p2 = blur_2.getpixel(coords) + + p1 = np.array(p1) + p2 = np.array(p2) + new_pixel = p2 - p1 + + dog.putpixel(coords, tuple(new_pixel.tolist())) + + return dog + +def sobel(img: Image.Image, gradient_threshold: int | None = 20) -> tuple[Image.Image, np.ndarray]: + logging.debug(img.size) + + img = img.convert('L') + img.save('debug/test-L.png') + + logging.debug('Sobel Operator') + + logging.debug(img.size) + + pixels = np.array(img) + logging.debug(f'pixels size: {pixels.size}') + + dx = scipy.signal.correlate(pixels, sobel_x_kernel, mode='same') + dy = scipy.signal.correlate(pixels, sobel_y_kernel, mode='same') + logging.debug(f'dx size: {dx.size}') + + edges = np.sqrt(np.square(dx) + np.square(dy)) + edges[edges>255] = 255 + + logging.debug(f'edges size: {edges.size}') + + gradient = np.arctan2(dy.flatten(), dx.flatten()) + gradient[gradient > gradient_threshold] = 0 + + pil_edges = edges.astype(np.uint8) + newimg = Image.fromarray(pil_edges, mode='L') + logging.debug(f'New Img Size: {newimg.size}') + + return (newimg, gradient) + diff --git a/sobel.py b/sobel.py index e4883a3..a871af3 100644 --- a/sobel.py +++ b/sobel.py @@ -1,19 +1,21 @@ # import scipy.ndimage as nd # import imageio.v3 as iio # import numpy as np +import logging import math import os -from PIL import Image, ImageFilter +from PIL import Image import pygame as pg -IMAGE_PATH = 'sample-images/sunflower.jpg' +import filters + +FORMAT = "%(levelname)s %(filename)s - %(message)s" +logging.basicConfig(level=logging.DEBUG, format=FORMAT) + +IMAGE_PATH = 'sample-images/engine.PNG' FONT_PATH = 'fonts/scientifica.ttf' -BLUR_STRENGTH_1 = 1 -BLUR_STRENGTH_2 = 1.2 - -DOG_THRESHOLD = 8 WHITE = (255,255,255) @@ -49,19 +51,17 @@ def main(): image = Image.open(IMAGE_PATH) image = image.resize((image.width * RESIZE_FACTOR, image.height * RESIZE_FACTOR)) + logging.debug(f'Image Size: {image.size}') L_image = image.convert('L') + logging.debug(f'L_image Size: {L_image.size}') - blur_1 = image.filter(ImageFilter.GaussianBlur(BLUR_STRENGTH_1)) - blur_2 = image.filter(ImageFilter.GaussianBlur(BLUR_STRENGTH_2)) - - - print(image.size) - dog: Image = difference_of_gaussians(blur_1, blur_2) + dog = filters.difference_of_gaussians(image) + logging.debug(f'Dog Size: {dog.size}') dog.save('dog.png') - sb, gradient = sobel(dog) + sb, gradient = filters.sobel(dog) w, h = sb.size @@ -191,126 +191,6 @@ def main(): pg.image.save(window, "debug/edges-render.png") pg.quit() - - - -def subtract_colors(t1: tuple, t2: tuple) -> tuple: - - if type(t1) != tuple: - if (t2 - t1) >= DOG_THRESHOLD: - return t2 - t1 - else: - return 0 - - if len(t1) != len(t2): - print('Len of first tuple should equal second tuple probably') - exit(1) - - ans = [] - for i, n in enumerate(t1): - ans.append(t2[i] - n) - - return tuple(ans) - -def difference_of_gaussians(blur_1: Image, blur_2: Image) -> Image: - - w, h = blur_1.size - - dog = Image.new(blur_1.mode, blur_1.size) - - for pixel_y in range(0, h): - for pixel_x in range(0, w): - - coords = (pixel_x, pixel_y) - - dog.putpixel(coords, subtract_colors(blur_2.getpixel(coords), blur_1.getpixel(coords))) - - return dog - -# Taken from -# https://enzoftware.github.io/posts/image-filter-python -def sobel(img: Image) -> tuple[Image.Image, list]: - if img.mode == 'L': - # return sobel_L(img) - pass - img = img.convert('RGB') - - width, height = img.size - - newimg = Image.new("RGB", (width, height), "white") - gradient = [None for x in range(0, width * height)] - for x in range(1, width - 1): # ignore the edge pixels for simplicity (1 to width-1) - for y in range(1, height - 1): # ignore edge pixels for simplicity (1 to height-1) - - # initialise Gx to 0 and Gy to 0 for every pixel - Gx = 0 - Gy = 0 - - # top left pixel - r, g, b = img.getpixel((x - 1, y - 1)) - - # intensity ranges from 0 to 765 (255 * 3) - intensity = r + g + b - - # accumulate the value into Gx, and Gy - Gx += -intensity - Gy += -intensity - - # remaining left column - r, g, b = img.getpixel((x-1, y)) - - Gx += -2 * (r + g + b) - - r, g, b = img.getpixel((x-1, y+1)) - - Gx += -(r + g + b) - Gy += (r + g + b) - - # middle pixels - r, g, b = img.getpixel((x, y-1)) - - Gy += -2 * (r + g + b) - - r, g, b = img.getpixel((x, y+1)) - - Gy += 2 * (r + g + b) - - # right column - r, g, b = img.getpixel((x+1, y-1)) - - Gx += (r + g + b) - Gy += -(r + g + b) - - r, g, b = img.getpixel((x+1, y)) - - Gx += 2 * (r + g + b) - - r, g, b = img.getpixel((x+1, y+1)) - - Gx += (r + g + b) - Gy += (r + g + b) - - # calculate the length of the gradient (Pythagorean theorem) - length = math.sqrt((Gx * Gx) + (Gy * Gy)) - - # normalise the length of gradient to the range 0 to 255 - length = length / 4328 * 255 - - length = int(length) - gradient_v = math.atan2(Gy, Gx) - # print(gradient_v) - - # draw the length in the edge image - #newpixel = img.putpixel((length,length,length)) - newimg.putpixel((x,y),(length,length,length)) - if length < 20: - gradient[y * width + x] = gradient_v - - return (newimg, gradient) - -def sobel_L(img: Image) -> tuple[Image.Image, list]: - pass - # TODO @0x01FE : refactor plz increment by 30 & 60 def match_gradient(n: float) -> str: