使用Python图像处理库进行透明PNG调整大小及其光晕效应

7
有几个类似的问题在SO上,但没有一个真正有用。基本上我正在尝试调整一个简单的png图像的大小,如下所示:http://media.spiralknights.com/wiki-images/3/3e/Equipment-Proto_Sword_icon.png(来自mmo Spiral Knights,版权归Three Rings Entertainment所有)。
我最初实现了一个在php中使用这些图像的实用程序,并且那里的调整大小实用程序完美地工作。我使用了PHP文档中描述的imagecopyresampled页面上的方法。
老实说,我甚至无法在Photoshop中更好地调整大小,但是在Python中结果几乎是灾难性的。我始终得到光圈效应,我认为这至少部分是由于透明像素的实际RGBA值。这里,这张图片讲述了更好的故事:
(倒数第二次调整大小只是我在另一个论坛上看到的建议,先将大小调整为最终大小的两倍,它确实有所帮助,但不够)
当图像被调整大小时,它已经处于RGBA模式中。
正如你所看到的,PHP和Photoshop的调整大小都没有光晕。老实说,除了PHP调整大小之外,其他所有调整大小都做得太多了,我喜欢php图像中的最小调色板(如果你查看较大的版本,则可以看到PHP调整大小使用更少的中间颜色),但是我可以接受Photoshop已经调整大小,甚至是Python调整大小的内部部分,但是光晕是不可接受的。
在我的调整大小中,似乎PHP和Photoshop似乎知道在插值时不要使用alpha通道中像素的颜色,但是Python正在使用那个轻微的边框,在其调整大小中除了透明之外。
不幸的是,我需要调整大小的不同图标有不同的配置文件,因此它们并不像这个圆形的那样简单,但是这只是我在尝试时使用的第一个图标。
这本身不是一个代码问题,但是如果您需要查看某些内容,那么这就是要点:
>> import Image
>> img = Image.open('swordorig.png')
>> img
<PngImagePlugin.PngImageFile image mode=RGBA size=256x256 at 0x2A3AF58>
>> img.resize((36,36), Image.ANTIALIAS).save('swordresize.png')

最终的问题是:有没有办法在重新采样时告诉PIL不要使用alpha为0的像素的颜色?


1
你不知道PIL吗?但是你尝试使用RGBa(而不是RGBA)来指示它考虑图像是否为预乘alpha了吗? - rotoglup
1
我之前没有尝试过,所以感谢您的建议!不幸的是,似乎PIL无法将RGBa写入png文件中。 “IOError:无法将RGBa模式写入PNG” - cogs
如果你喜欢 Photoshop Bicubic 的结果,也许 Image.BICUBIC 或者 Image.NEAREST 会更好?http://pastebin.com/VRBKWZUh - reclosedev
不幸的是,Image.BICUBIC和NEAREST处理得太少,导致很多锯齿。我可能最终还是会选择它,因为它仍然比光晕好,但并不理想。 - cogs
1
我会尝试在Python中使用OpenCV,有很多插值技术可供选择,比如双线性插值、双三次插值等。http://opencv.willowgarage.com/documentation/python/imgproc_geometric_image_transformations.html#resize - Sam Felix
谢谢提供的参考!我也会去看看!我刚刚找到了一个可行的解决方案(感谢rotoglup告诉我它叫做预乘alpha!),但我还需要等5个小时才能回答自己的问题。叹气那时候我会更新的。 - cogs
1个回答

7
感谢大家的回答!特别感谢rotoglup告诉我我实际上正在寻找的术语。通过查看PIL中预乘alpha的堆栈溢出页面,我找到了一个可行的解决方案;这是更新后的调整图形表格: resize sheet 2 灰色条只是给人们留下在浅色背景上会是什么样子的印象。 https://dev59.com/FVjUa4cB1Zd3GeqPV_L8#6882161 感谢madlag
因此,我的代码最终看起来像这样:
>> import Image, numpy
>> img = Image.open('swordorig.png')
>> premult = numpy.fromstring(img.tostring(), dtype=numpy.uint8)
>> alphaLayer = premult[3::4] / 255.0
>> premult[::4] *= alphaLayer
>> premult[1::4] *= alphaLayer
>> premult[2::4] *= alphaLayer
>> img = Image.fromstring("RGBA", img.size, premult.tostring())
>> img.resize((36,36), Image.ANTIALIAS).save('swordresize.png')

你将获得在底部的图标。颜色比PHP版本多,有一个非常温和的环形,但总体上更漂亮。我相信算法可以被调整以进一步改善它。再次感谢所有人的回应!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接