diff --git a/convert.py b/convert.py index 51d1c92..5171b21 100644 --- a/convert.py +++ b/convert.py @@ -4,6 +4,8 @@ import argparse import array import os.path import time +import collections +import random import colour from PIL import Image @@ -23,15 +25,27 @@ import screen as screen_py def cluster_palette(image: Image): + shuffle_lines = list(range(200)) + random.shuffle(shuffle_lines) + line_to_palette = {} + for idx, line in enumerate(shuffle_lines): + line_to_palette[line] = idx % 16 + colours_rgb = np.asarray(image).reshape((-1, 3)) with colour.utilities.suppress_warnings(colour_usage_warnings=True): colours_cam = colour.convert(colours_rgb, "RGB", "CAM16UCS").astype(np.float32) palettes_rgb = {} + palette_colours = collections.defaultdict(list) + for line in range(200): + palette = line_to_palette[line] + palette_colours[palette].extend( + colours_cam[line * 320:(line + 1) * 320]) + for palette in range(16): kmeans = KMeans(n_clusters=16, max_iter=10000) - kmeans.fit_predict(colours_cam[palette*320*12:(palette+1)*320*12]) + kmeans.fit_predict(palette_colours[palette]) palette_cam = kmeans.cluster_centers_ with colour.utilities.suppress_warnings(colour_usage_warnings=True): palette_rgb = colour.convert(palette_cam, "CAM16UCS", "RGB") @@ -39,8 +53,7 @@ def cluster_palette(image: Image): palette_rgb = np.round(palette_rgb * 15) / 15 # palette_rgb = palette_rgb.astype(np.float32) / 255 palettes_rgb[palette] = palette_rgb.astype(np.float32) - return palettes_rgb - + return palettes_rgb, line_to_palette def main(): @@ -103,22 +116,22 @@ def main(): gamma=args.gamma_correct, srgb_output=True)).astype( np.float32) / 255 - palettes_rgb = cluster_palette(rgb) + palettes_rgb, line_to_palette = cluster_palette(rgb) # print(palette_rgb) # screen.set_palette(0, (image_py.linear_to_srgb_array(palette_rgb) * # 15).astype(np.uint8)) for i, p in palettes_rgb.items(): screen.set_palette(i, (np.round(p * 15)).astype(np.uint8)) - output_4bit = dither_pyx.dither_shr(rgb, palettes_rgb, rgb_to_cam16) + output_4bit = dither_pyx.dither_shr(rgb, palettes_rgb, rgb_to_cam16, + line_to_palette) screen.set_pixels(output_4bit) - for i in range(200): - screen.line_palette[i] = i // 12 output_rgb = np.zeros((200, 320, 3), dtype=np.uint8) - for i, p in palettes_rgb.items(): - output_rgb[i*12:(i+1)*12, :, :] = (p[output_4bit[i*12:(i+1)*12, - :]] * 255).astype( - np.uint8) + for i in range(200): + screen.line_palette[i] = line_to_palette[i] + output_rgb[i, :, :] = ( + palettes_rgb[line_to_palette[i]][ + output_4bit[i, :]] * 255).astype(np.uint8) output_srgb = image_py.linear_to_srgb(output_rgb).astype(np.uint8) # dither = dither_pattern.PATTERNS[args.dither]() diff --git a/dither.pyx b/dither.pyx index 8524d56..8029de7 100644 --- a/dither.pyx +++ b/dither.pyx @@ -328,7 +328,7 @@ import colour @cython.boundscheck(False) @cython.wraparound(False) -def dither_shr(float[:, :, ::1] working_image, object palettes_rgb, float[:,::1] rgb_to_cam16ucs): +def dither_shr(float[:, :, ::1] working_image, object palettes_rgb, float[:,::1] rgb_to_cam16ucs, object line_to_palette): cdef int y, x, idx, best_colour_idx cdef float best_distance, distance cdef float[::1] best_colour_rgb, pixel_cam, colour_rgb, colour_cam @@ -337,9 +337,9 @@ def dither_shr(float[:, :, ::1] working_image, object palettes_rgb, float[:,::1] cdef (unsigned char)[:, ::1] output_4bit = np.zeros((200, 320), dtype=np.uint8) - for y in range(192): + for y in range(200): print(y) - palette_rgb = palettes_rgb[y // 12] + palette_rgb = palettes_rgb[line_to_palette[y]] for x in range(320): pixel_cam = convert_rgb_to_cam16ucs( rgb_to_cam16ucs, working_image[y, x, 0], working_image[y, x, 1], working_image[y, x, 2])