使用PIL的Image.merge时出现段错误

2 投票
2 回答
45 浏览
提问于 2025-04-14 16:13

我有一张600x600像素的RGB图片,我想创建一张新图片,RGB通道的值要从原图进行如下转换:(R, G, B) -> (R-1.4*B, G, B)。我使用绝对值来确保RGB的值都是正数。以下是我用来实现这个转换的代码,但运行时出现了段错误(segfault):

            r, g, b = original.split()                 #split image into (r, g, b) channels

            r = abs(np.array(r)-1.4*np.array(b))       #apply transformation
            
            r = Image.fromarray(r)                     #revert r to PIL Image object
            
            result = Image.merge('RGB', (r, g, b))     #merge channels to create new image

            result.show()

运行这段代码时,输出结果是:

zsh: segmentation fault /Users/arjunchandra/miniconda3/envs/bbox_env/bin/python

当我把调用Image.merge的那一行注释掉时,段错误就消失了,但我不太明白为什么。如果有人能给我一些建议,告诉我为什么会出现段错误,或者如何解决这个问题,或者检查内存情况,请告诉我。另外,如果你能推荐其他方法来进行这个转换,那就太好了。

这个方法给了我一些其他转换图片的思路,但对于矩阵的方法,我不太确定如何使用(R-1.4B)的绝对值。而且我怀疑把图片转换成numpy数组,然后手动更改每个像素的RGB值效率会很低,因为我有很多图片需要进行这种转换。

2 个回答

1

红色通道的值超出了PIL对象允许的范围(0到255)。你需要把这些值限制在这个范围内:

r = Image.fromarray(r.clip(0, 255))
1

给@MSiddons点赞,感谢他发现了问题的关键所在——也就是减法运算的结果超出了np.uint8的范围,因此需要把结果限制在正确的范围内。

还有一个复杂的地方是,和浮点数(1.4)相乘后,得到的红色通道变成了浮点图像,而原来的绿色和蓝色通道是np.uint8类型的,这样就无法直接合并,所以还需要进行一次类型转换。

import numpy as np
from PIL import Image

# Create a purpley image such that B exceeds R
im = Image.new('RGB', (256,256), '#800090')

在这里输入图片描述

# Split image into constituent bands
r, g, b = im.split()

# Do the maths
r = abs(np.array(r)-1.4*np.array(b))

# Crucial line... force back to np.uint8
r = Image.fromarray(r.astype(np.uint8))

# Problem solved
result = Image.merge('RGB', (r, g, b))

现在我们可以检查一下结果:

print(result.getpixel((0,0)))

(73, 0, 144)

还有

red (73) = original red (0x80) - 1.4 * blue (0x90)

撰写回答