假设您想要缩放透明图像但尚不知道背景的颜色,您将在以后将其合成。不幸的是,PIL似乎包含完全透明像素的颜色值,导致不良结果。有没有办法告诉PIL-resize忽略完全透明的像素?
import PIL.Image
filename = "trans.png" # http://qrc-designer.com/stuff/trans.png
size = (25,25)
im = PIL.Image.open(filename)
print im.mode # RGBA
im = im.resize(size, PIL.Image.LINEAR) # the same with CUBIC, ANTIALIAS, transform
# im.show() # does not use alpha
im.save("resizelinear_"+filename)
# PIL scaled image has dark border
带有(0,0,0,0)(黑色但完全透明)背景的原始图像(左)
输出带黑晕的图像(中)
使用gimp缩放正确的输出(右)
编辑:看起来要实现我正在寻找的东西我将不得不修改调整大小函数本身的采样,以便它会忽略具有完全透明度的像素。
edit2:我发现了一个非常难看的解决方案。它将完全透明像素的颜色值设置为周围非完全透明像素的平均值,以最大限度地减小调整大小时完全透明像素颜色的影响。它在简单的形式中很慢,但如果没有其他解决方案,我会发布它。通过使用扩张操作来处理必要的像素,可能会使速度更快。
edit3:预乘alpha是要走的路 - 请参阅Mark的回答
答案 0 :(得分:4)
看来PIL在调整大小之前不会进行alpha预乘,这对于获得正确的结果是必要的。幸运的是,蛮力很容易做到。然后,您必须反向调整大小后的结果。
def premultiply(im):
pixels = im.load()
for y in range(im.size[1]):
for x in range(im.size[0]):
r, g, b, a = pixels[x, y]
if a != 255:
r = r * a // 255
g = g * a // 255
b = b * a // 255
pixels[x, y] = (r, g, b, a)
def unmultiply(im):
pixels = im.load()
for y in range(im.size[1]):
for x in range(im.size[0]):
r, g, b, a = pixels[x, y]
if a != 255 and a != 0:
r = 255 if r >= a else 255 * r // a
g = 255 if g >= a else 255 * g // a
b = 255 if b >= a else 255 * b // a
pixels[x, y] = (r, g, b, a)
结果:
答案 1 :(得分:2)
您可以单独重新取样每个乐队:
im.load()
bands = im.split()
bands = [b.resize(size, Image.LINEAR) for b in bands]
im = Image.merge('RGBA', bands)
修改强>
也许避免像这样的高透明度值(需要numpy)
import numpy as np
# ...
im.load()
bands = list(im.split())
a = np.asarray(bands[-1])
a.flags.writeable = True
a[a != 0] = 1
bands[-1] = Image.fromarray(a)
bands = [b.resize(size, Image.LINEAR) for b in bands]
a = np.asarray(bands[-1])
a.flags.writeable = True
a[a != 0] = 255
bands[-1] = Image.fromarray(a)
im = Image.merge('RGBA', bands)
答案 2 :(得分:0)
也许你可以用你想要的颜色填充整个图像,只在alpha channnel中创建形状?
答案 3 :(得分:0)
非常难看和缓慢。如果你能想出更好的东西,我会很乐意接受你的回答。
# might be possible to speed this up by only processing necessary pixels
# using scipy dilate, numpy where
import PIL.Image
filename = "trans.png" # http://qrc-designer.com/stuff/trans.png
size = (25,25)
import numpy as np
im = PIL.Image.open(filename)
npImRgba = np.asarray(im, dtype=np.uint8)
npImRgba2 = np.asarray(im, dtype=np.uint8)
npImRgba2.flags.writeable = True
lenY = npImRgba.shape[0]
lenX = npImRgba.shape[1]
for y in range(npImRgba.shape[0]):
for x in range(npImRgba.shape[1]):
if npImRgba[y, x, 3] != 0: # only change completely transparent pixels
continue
colSum = np.zeros((3), dtype=np.uint16)
i = 0
for oy in [-1, 0, 1]:
for ox in [-1, 0, 1]:
if not oy and not ox:
continue
iy = y + oy
if iy < 0:
continue
if iy >= lenY:
continue
ix = x + ox
if ix < 0:
continue
if ix >= lenX:
continue
col = npImRgba[iy, ix]
if not col[3]:
continue
colSum += col[:3]
i += 1
npImRgba2[y, x, :3] = colSum / i
im = PIL.Image.fromarray(npImRgba2)
im = im.transform(size, PIL.Image.EXTENT, (0,0) + im.size, PIL.Image.LINEAR)
im.save("slime_"+filename)
结果: