如何使用Python实现图像自定义调色板渐变映射效果
Python实现自定义调色板渐变映射完整方案
大多数图像编辑软件内置的渐变映射功能逻辑是读取单像素亮度值,按亮度等级匹配对应渐变色。Photoshop类软件的自动化渐变映射无法灵活适配定制化需求,纯Python实现可以避开numpy、matplotlib库的复杂数学逻辑,仅用PIL即可完成功能开发。

核心实现逻辑
你已经完成了图像加载、亮度计算、结果保存的基础框架,缺失的亮度到渐变色的映射可以按以下步骤实现,不需要依赖额外数值计算库:
- 先把十六进制格式的调色板色值转换为0-255区间的RGB三元组
- 将0-255的全亮度范围,按照调色板的颜色数量等分为若干过渡段:n个颜色对应n-1个过渡段
- 判断像素亮度所属的过渡段,计算亮度在该段内的相对占比,对段两端的颜色做三通道线性插值,得到最终映射色
完整可运行代码
from PIL import Image # 自定义调色板,支持任意数量的十六进制色值 myPalette = ['#1A1423', '#684756', '#AB8476'] def hex_to_rgb(hex_color): """工具函数:把十六进制色值转成(R,G,B)三元组""" hex_color = hex_color.lstrip('#') return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) def colorMap(pixel, palette): R, G, B = pixel # 计算亮度:如果要更符合人眼感知,可以替换为加权亮度 brightness = 0.299*R + 0.587*G + 0.114*B brightness = sum([R, G, B]) / 3 # 预处理调色板为RGB格式 palette_rgb = [hex_to_rgb(color) for color in palette] color_count = len(palette_rgb) # 边界情况:亮度为0直接返回第一个颜色,亮度为255直接返回最后一个颜色 if brightness <= 0: return palette_rgb[0] if brightness >= 255: return palette_rgb[-1] # 计算当前亮度对应的过渡段位置 segment_length = 255 / (color_count - 1) segment_index = int(brightness // segment_length) # 计算当前亮度在所属过渡段内的比例(0-1之间) ratio = (brightness - segment_index * segment_length) / segment_length # 取过渡段两端的颜色 color_start = palette_rgb[segment_index] color_end = palette_rgb[segment_index + 1] # 三通道分别线性插值得到最终颜色 mapped_r = int(color_start[0] * (1 - ratio) + color_end[0] * ratio) mapped_g = int(color_start[1] * (1 - ratio) + color_end[1] * ratio) mapped_b = int(color_start[2] * (1 - ratio) + color_end[2] * ratio) return (mapped_r, mapped_g, mapped_b) img = Image.open('image_input.png') pixels = img.load() for x in range(img.size[0]): for y in range(img.size[1]): pixel = img.getpixel((x, y)) pixels[x, y] = colorMap(pixel, myPalette) img.save('image_output.png')
可调优化点
- 可以修改亮度计算公式,替换为人眼感知加权亮度,映射效果会更接近Photoshop的默认渐变映射结果
- 调色板支持传入任意数量的色值,不需要修改函数逻辑,颜色之间会自动生成平滑过渡
- 如果需要硬边映射不需要渐变,把插值逻辑替换为直接取最近的调色板颜色即可
内容的提问来源于stack exchange,提问作者axe
相关产品推荐
相关产品推荐

