From fb52815412222af23b67ccce2fb4e7a8924e315f Mon Sep 17 00:00:00 2001 From: kris Date: Tue, 9 Nov 2021 22:42:27 +0000 Subject: [PATCH] Experiment with striping 16 palettes contiguously across line ranges. As expected it has clear banding. A better approach (though still not optimal) might be to assign lines to palettes randomly. --- convert.py | 36 +++++++++++++++++++++++------------- dither.pyx | 6 ++++-- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/convert.py b/convert.py index 369603f..51d1c92 100644 --- a/convert.py +++ b/convert.py @@ -28,15 +28,18 @@ def cluster_palette(image: Image): colours_cam = colour.convert(colours_rgb, "RGB", "CAM16UCS").astype(np.float32) - kmeans = KMeans(n_clusters=16, max_iter=10000) - kmeans.fit_predict(colours_cam) - palette_cam = kmeans.cluster_centers_ - with colour.utilities.suppress_warnings(colour_usage_warnings=True): - palette_rgb = colour.convert(palette_cam, "CAM16UCS", "RGB") - # SHR colour palette only uses 4-bit values - palette_rgb = np.round(palette_rgb * 15) / 15 - # palette_rgb = palette_rgb.astype(np.float32) / 255 - return palette_rgb.astype(np.float32) + palettes_rgb = {} + 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]) + palette_cam = kmeans.cluster_centers_ + with colour.utilities.suppress_warnings(colour_usage_warnings=True): + palette_rgb = colour.convert(palette_cam, "CAM16UCS", "RGB") + # SHR colour palette only uses 4-bit values + 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 @@ -100,15 +103,22 @@ def main(): gamma=args.gamma_correct, srgb_output=True)).astype( np.float32) / 255 - palette_rgb = cluster_palette(rgb) + palettes_rgb = cluster_palette(rgb) # print(palette_rgb) # screen.set_palette(0, (image_py.linear_to_srgb_array(palette_rgb) * # 15).astype(np.uint8)) - screen.set_palette(0, (np.round(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, palette_rgb, rgb_to_cam16) + output_4bit = dither_pyx.dither_shr(rgb, palettes_rgb, rgb_to_cam16) screen.set_pixels(output_4bit) - output_rgb = (palette_rgb[output_4bit] * 255).astype(np.uint8) + 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) 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 fc23520..8524d56 100644 --- a/dither.pyx +++ b/dither.pyx @@ -328,16 +328,18 @@ import colour @cython.boundscheck(False) @cython.wraparound(False) -def dither_shr(float[:, :, ::1] working_image, float[:, ::1] palette_rgb, float[:,::1] rgb_to_cam16ucs): +def dither_shr(float[:, :, ::1] working_image, object palettes_rgb, float[:,::1] rgb_to_cam16ucs): 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 cdef float[3] quant_error + cdef float[:, ::1] palette_rgb cdef (unsigned char)[:, ::1] output_4bit = np.zeros((200, 320), dtype=np.uint8) - for y in range(200): + for y in range(192): print(y) + palette_rgb = palettes_rgb[y // 12] 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])