Pillow库实现图像指定颜色替换功能的方法
Pillow 指定颜色替换方案
内置函数说明
Pillow 没有提供直接替换图像内指定颜色的专属内置函数,不过可以通过其像素操作接口,或搭配Numpy快速实现高性能的颜色替换功能。
现有代码问题
你当前编写的代码存在3个核心问题,会导致运行报错或替换不生效:
- 每次调用
fill_color都会重新从原始base_img生成numpy数组,前一次替换的结果会被下一次调用覆盖 putdata方法接收一维像素序列作为入参,直接传入三维numpy数组会触发维度不匹配错误- 没有兼容带Alpha透明通道的PNG图像,多出来的通道会导致颜色匹配逻辑失效
可直接运行的实现代码
提供两种实现方案,优先推荐Numpy加速版本,处理大图性能远高于逐像素遍历。
Numpy加速版本(推荐)
支持自定义颜色容差,可处理带压缩噪点的非完全纯色图片,处理速度快:
from PIL import Image import random import numpy as np def replace_color(img_arr, target_color, replace_color, tolerance=0): """ 颜色替换函数 :param img_arr: 图像转换得到的numpy数组 :param target_color: 需要替换的原始颜色,传入(R,G,B)格式元组 :param replace_color: 替换后的目标颜色,传入(R,G,B)格式元组 :param tolerance: 颜色匹配容差,0为完全精确匹配,值越大允许的颜色偏差越高 """ # 提取RGB通道做匹配,忽略Alpha通道避免匹配失败 rgb_part = img_arr[..., :3] # 生成需要替换的像素掩码 diff = np.abs(rgb_part - np.array(target_color[:3])) match_mask = np.all(diff <= tolerance, axis=-1) # 执行替换 img_arr[match_mask, :len(replace_color)] = replace_color return img_arr def color_adjust(base_color, offset): """颜色明暗偏移调整""" return tuple(max(0, min(255, c + offset)) for c in base_color) if __name__ == "__main__": main_color = (0, 0, 255) # 读取图像统一转RGBA模式,兼容带透明通道的PNG base_img = Image.open("./base.png").convert("RGBA") img_arr = np.array(base_img) # 配置需要替换的颜色映射关系 replace_map = [ ((127, 255, 255), (random.randint(128,255), random.randint(128,255), random.randint(128,255), 255)), ((255, 0, 0), (*color_adjust(main_color, 50), 255)), ((255, 128, 0), (*color_adjust(main_color, 25), 255)), ((255, 255, 0), (*main_color, 255)) ] # 批量执行替换 for old_c, new_c in replace_map: img_arr = replace_color(img_arr, old_c, new_c, tolerance=0) # 转回图像对象展示/保存 res_img = Image.fromarray(img_arr) res_img.show() # res_img.save("./result.png")
如果你的图片经过压缩存在颜色噪点,不存在完全精准的纯色块,把tolerance参数调整到5~15即可匹配相近颜色完成替换。
纯Pillow实现(无额外依赖)
不需要安装Numpy,逻辑简单,仅适合处理小尺寸图片,大尺寸图运行速度较慢:
from PIL import Image import random def replace_color_pure_pil(img, target_color, replace_color, tolerance=0): px = img.load() w, h = img.size tr, tg, tb = target_color[:3] for x in range(w): for y in range(h): cur = px[x,y] cr, cg, cb = cur[:3] if abs(cr-tr)<=tolerance and abs(cg-tg)<=tolerance and abs(cb-tb)<=tolerance: px[x,y] = (*replace_color, cur[3]) if len(cur)==4 else replace_color return img def color_adjust(base_color, offset): return tuple(max(0, min(255, c + offset)) for c in base_color) if __name__ == "__main__": main_color = (0, 0, 255) base_img = Image.open("./base.png").convert("RGBA") replace_list = [ ((127, 255, 255), (random.randint(128,255), random.randint(128,255), random.randint(128,255))), ((255, 0, 0), color_adjust(main_color, 50)), ((255, 128, 0), color_adjust(main_color, 25)), ((255, 255, 0), main_color) ] for old_c, new_c in replace_list: base_img = replace_color_pure_pil(base_img, old_c, new_c) base_img.show()
内容的提问来源于stack exchange,提问作者HellishBro
相关产品推荐
相关产品推荐

