Python复现GIMP Addition图层混合模式与原生效果不一致如何解决
核心问题原因
你目前的代码是直接在伽马编码的sRGB空间对像素值做加法,而GIMP 2.10及以上版本默认启用线性空间混合,Addition模式的运算会先把两个图层的像素从伽马校正的sRGB空间转换到线性RGB空间,执行加法截断后再转换回sRGB空间输出,这是两者结果存在亮度差异的核心原因。
复现GIMP Addition模式的代码
import cv2 import numpy as np from PIL import Image def srgb_to_linear(img): # 输入为0-255的uint8 sRGB图像,输出0-1范围的线性RGB数组 img = img.astype(np.float32) / 255.0 mask = img <= 0.04045 img[mask] = img[mask] / 12.92 img[~mask] = np.power((img[~mask] + 0.055) / 1.055, 2.4) return img def linear_to_srgb(img): # 输入为0-1范围的线性RGB数组,输出0-255的uint8 sRGB图像 mask = img <= 0.0031308 img[mask] = img[mask] * 12.92 img[~mask] = 1.055 * np.power(img[~mask], 1/2.4) - 0.055 return (img * 255).astype(np.uint8) # 读取图像 diffuse = cv2.imread('diffuse.png') reflection = cv2.imread('reflection.png') # 转RGB diffuse = cv2.cvtColor(diffuse, cv2.COLOR_BGR2RGB) reflection = cv2.cvtColor(reflection, cv2.COLOR_BGR2RGB) # 转线性空间 linear_diffuse = srgb_to_linear(diffuse) linear_reflection = srgb_to_linear(reflection) # 线性空间执行饱和加法 linear_add = np.clip(linear_diffuse + linear_reflection, 0.0, 1.0) # 转回sRGB空间 result = linear_to_srgb(linear_add) # 保存 im = Image.fromarray(result) im.save('blended_python.png')
额外注意事项
- 如果你的GIMP关闭了线性空间混合选项(路径:编辑→首选项→图像默认值→默认混合空间),不需要做伽马转换,直接调用
cv2.add(diffuse, reflection)就能得到完全一致的结果,该函数原生支持饱和运算,不需要手动转类型做截断。 - 如果图像带有alpha透明通道,读取时需要添加
cv2.IMREAD_UNCHANGED参数,混合前需要先做预乘alpha处理,避免透明区域出现色偏。
内容的提问来源于stack exchange,提问作者Mitchell van Zuylen
相关产品推荐
相关产品推荐

