1

我正在尝试将两个图像添加在一起。

在此处输入图像描述

在此处输入图像描述

当我在 GIMP 中这样做时,使用“添加”图层模式,我得到以下所需的输出。 在此处输入图像描述

现在,我正在尝试在 Python 中执行此操作,但是我无法使其正常工作。根据 gimp 文档,据我了解,加法公式只是每个像素的加法,最大值设置为 255。

加法模式方程:E = min(( M + I ), 255)

我尝试在 Python 中应用它,但输出看起来不同。如何在 Python 中获得与 gimp 添加层混合模式相同的输出?

我的尝试:

# Load in the images
diffuse = cv2.imread('diffuse.png')
reflection = cv2.imread('reflection.png',)
# Convert BGR to RGB
diffuse = cv2.cvtColor(diffuse, cv2.COLOR_BGR2RGB)
reflection = cv2.cvtColor(reflection, cv2.COLOR_BGR2RGB)
# Covnert to uint64 so values can overflow 255
diffuse = diffuse.astype('uint64')
reflection = reflection.astype('uint64')
added = diffuse + reflection # actually add
# clamp values above 255 to be 255
added[added > 255] = 255

# display 
im = Image.fromarray(added.astype('uint8'))
im.save('blended_python.png')

现在,这看起来非常相似,但与 GIMP 添加相比,它实际上太亮了。只需在新选项卡和它们之间的 alt+tab 中打开两者,差异就会变得明显。
在此处输入图像描述

如何获得与 GIMP 完全相同的结果?我尝试使用 Python-fu 或 gimp 批处理渲染(因为我有成千上万的图像想要像这样混合),但我也无法让它工作。

4

1 回答 1

1

在用户 Quang Hoang 的帮助下,我了解到 GIMP 默认情况下在应用添加之前对两个图层进行隐式转换(sRGB 到线性 sRGB)。

因此,要在 python 中重新创建这种行为,我们需要以下函数来从 sRGB 到线性 sRGB 来回转换。受此问题此答案启发的功能。

def srgb_to_linsrgb(srgb):
    # takes np array as input in sRGB color space and convert to linear sRGB
    gamma = pow(((srgb + 0.055) / 1.055), 2.4)
    scale = srgb / 12.92
    return np.where (srgb > 0.04045, gamma, scale)


def linsrgb_to_srgb(lin):
    # takes np array as input in linear sRGB color space and convert to sRGB
    gamma =  1.055 * (pow(lin, (1.0 / 2.4))) - 0.055
    scale =  12.92 * lin
    return np.where(lin > 0.0031308,  gamma, scale)

然后我们只需将这些函数添加到原始问题的现有代码中。

# Load in the images
diffuse = cv2.imread('diffuse.png')
reflection = cv2.imread('reflection.png',)

# Convert BGR to RGB
diffuse = cv2.cvtColor(diffuse, cv2.COLOR_BGR2RGB)
reflection = cv2.cvtColor(reflection, cv2.COLOR_BGR2RGB)

# Convert to sRGB in linear space
lin_diffuse = srgb_to_linsrgb(diffuse)
lin_reflection = srgb_to_linsrgb(reflection)

lin_added = lin_diffuse + lin_reflection # actually add
added = linsrgb_to_srgb(lin_added)
added[added > 255] = 255

# # display 
im = Image.fromarray(added.astype('uint8'))
于 2021-12-06T05:26:47.970 回答