from PIL import Image def hex_to_rgb(value): value = value.lstrip('#') length = len(value) return tuple(int(value[i:i + length // 3], 16) for i in range(0, length, length // 3)) def luminance(color): # Use the ITU-R BT.709 formula r, g, b = color return 0.2126 * r + 0.7152 * g + 0.0722 * b # def interpolate_color(color1, color2, factor): # return tuple(int(c1 * (1 - factor) + c2 * factor) for c1, c2 in zip(color1, color2)) def quadratic_interpolate(factor): #make the interpolation closer to the second color return factor ** 2 def interpolate_color(color1, color2, factor): adjusted_factor = quadratic_interpolate(factor) return tuple(int(c1 * (1 - adjusted_factor) + c2 * adjusted_factor) for c1, c2 in zip(color1, color2)) def remap_image_colors(image_path, hex_palette): # img = Image.open(image_path) img = Image.fromarray(image_path) rgb_palette = [hex_to_rgb(hex_code) for hex_code in hex_palette] sorted_palette = sorted(rgb_palette, key=luminance) img_rgb = img.convert("RGB") pixels = img_rgb.load() for y in range(img.height): for x in range(img.width): original_color = pixels[x, y] lum = luminance(original_color) # Find the closest palette colors by luminance (one darker, one brighter) prev_color = sorted_palette[0] next_color = sorted_palette[-1] for i in range(1, len(sorted_palette)): if luminance(sorted_palette[i]) > lum: next_color = sorted_palette[i] prev_color = sorted_palette[i-1] break # Interpolate between the two closest colors lum_range = luminance(next_color) - luminance(prev_color) if lum_range == 0: mapped_color = prev_color else: factor = (lum - luminance(prev_color)) / lum_range mapped_color = interpolate_color(prev_color, next_color, factor) pixels[x, y] = mapped_color img_rgb.save("result.jpg") # hex_palette = ['#db5a1e', '#555115', '#9a690e', '#1f3a19', '#da8007', '#9a0633', '#b70406', '#d01b4b', '#e20b0f', '#f7515d'] # remap_image_colors('estampa.jpg', hex_palette)