使用PIL的Image.merge时出现段错误
我有一张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)