diff --git a/sobel.py b/sobel.py index f682cd2..bd1db3c 100644 --- a/sobel.py +++ b/sobel.py @@ -3,15 +3,27 @@ import numpy as np import math from PIL import Image, ImageFilter +import pygame as pg -IMAGE_PATH = 'sample-images/engine.PNG' +IMAGE_PATH = 'sample-images/sunflower.jpg' BLUR_STRENGTH_1 = 1 -BLUR_STRENGTH_2 = 3 +BLUR_STRENGTH_2 = 2.5 DOG_THRESHOLD = 8 -CHARS = [ +WHITE = (255,255,255) + +TEXT_WIDTH = 6 # on font size 12 monocraft medium +TEXT_HEIGHT = 11 + +SCALE_FACTOR = 2 + +SCALED_WIDTH = math.floor(TEXT_WIDTH / SCALE_FACTOR) +SCALED_HEIGHT = math.floor(TEXT_HEIGHT / SCALE_FACTOR) + + +CHARS = list(reversed([ ' ', '.', '_', @@ -22,13 +34,13 @@ CHARS = [ 'B', '&', '#' -] +])) def main(): image = Image.open(IMAGE_PATH) - # image = image.convert('L') + L_image = image.convert('L') blur_1 = image.filter(ImageFilter.GaussianBlur(BLUR_STRENGTH_1)) blur_2 = image.filter(ImageFilter.GaussianBlur(BLUR_STRENGTH_2)) @@ -37,7 +49,9 @@ def main(): print(image.size) dog: Image = difference_of_gaussians(blur_1, blur_2) - print(dog.size) + dog.save('dog.png') + + # print(dog.size) # sb = sobel(image) @@ -47,15 +61,90 @@ def main(): w, h = sb.size - print(w * h) - print(sb.size) - print(len(gradient)) - exit() + # print(w * h) + # print(sb.size) + # print(len(gradient)) + # exit() + + sb.save('sobel.png') + + text_grid_width = w / SCALED_WIDTH + text_grind_height = h / SCALED_HEIGHT + + pg.init() + font = pg.font.SysFont("Monocraft Medium", 12) + window = pg.display.set_mode((text_grid_width * TEXT_WIDTH, text_grind_height * TEXT_HEIGHT)) + + y_offset = 0 + + for y in range(math.floor(h / SCALED_HEIGHT)): + x_offset = 0 + + for x in range(math.floor(w / SCALED_WIDTH)): + histogram = {} + + # Collect the most common char for a group of pixels + colors = [] + + for y2 in range(SCALED_HEIGHT): + for x2 in range(SCALED_WIDTH): + + real_x = x2 + x_offset + real_y = y2 + y_offset + + gradient_v = gradient[real_y * w + real_x] + + char = ' ' + + if gradient_v: + char = match_gradient(gradient_v) + else: + char = CHARS[round(L_image.getpixel((real_x, real_y))/(255/10)) - 1] + + if char in histogram: + histogram[char] += 1 + else: + histogram[char] = 1 + + colors.append(image.getpixel((real_x, real_y))) + + color_avg = average_colors(colors) + + # get most common + most_common = None + score = float('-inf') + for char in histogram: + if histogram[char] > score: + score = histogram[char] + most_common = char + + rendered_char = font.render(most_common, 1, color_avg) + window.blit(rendered_char, (x * TEXT_WIDTH, y * TEXT_HEIGHT)) + + x_offset += SCALED_WIDTH + + y_offset += SCALED_HEIGHT + + + + # for y in range(0, text_grind_height): + # for x in range(0, text_grid_width): + # gradient_v = gradient[y * (w * TEXT_WIDTH) + x] + + # char = ' ' + + # if gradient_v: + # char = match_gradient(gradient_v) + # else: + # char = CHARS[round(L_image.getpixel((x, y))/(255/10)) - 1] + + # rendered_char = font.render(char, 1, WHITE) + # window.blit(rendered_char, (x * TEXT_WIDTH, y * TEXT_HEIGHT)) + + pg.display.update() + pg.image.save(window, "render.png") + pg.quit() - for y in range(0, h): - for x in range(0, w): - gradient_v = gradient[y * (w - 1) + x] - print(match_gradient(gradient_v)) sb.save('sobel-dog.png') @@ -117,12 +206,14 @@ def difference_of_gaussians(blur_1: Image, blur_2: Image) -> Image: # https://enzoftware.github.io/posts/image-filter-python def sobel(img: Image) -> tuple[Image.Image, list]: if img.mode == 'L': - return sobel_L(img) + # return sobel_L(img) + pass + img = img.convert('RGB') width, height = img.size newimg = Image.new("RGB", (width, height), "white") - gradient = [] + 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) @@ -187,7 +278,8 @@ def sobel(img: Image) -> tuple[Image.Image, list]: # draw the length in the edge image #newpixel = img.putpixel((length,length,length)) newimg.putpixel((x,y),(length,length,length)) - gradient.append(gradient_v) + if length < 20: + gradient[y * width + x] = gradient_v return (newimg, gradient) @@ -200,25 +292,35 @@ def match_gradient(n: float) -> str: n = abs(n) if n < math.radians(30): - return '-' + return '|' elif n < math.radians(60): return '/' elif n < math.radians(120): - return '|' + return '-' elif n < math.radians(150): return '\\' elif n < math.radians(210): - return '-' + return '|' elif n < math.radians(240): return '/' elif n < math.radians(300): - return '|' + return '-' elif n < math.radians(330): return '\\' else: - return '-' + return '|' +def average_colors(colors: list): + avg = [0 for x in range(len(colors[0]))] + for color in colors: + for i, num in enumerate(color): + avg[i] += num + + for i, n in enumerate(avg): + avg[i] /= len(colors) + + return avg if __name__ == '__main__': main()