本文首先叙述一段经历,然后得出结论,想看结论的可以直接跳到最后
经历
用一张带Alpha通道的PNG图片作为原始输入,然后用常用的PNG图片压缩工具pngquant处理得到压缩后的图片
(图片来源: super-mario-odyssey-switch)
压缩后图片从144 KB减小到39KB,而且几乎观察不到区别,但这不是本文重点
接下来使用结构相似性算法(Structural Similarity Index,SSIM)求出两张图片的相似程度,主要的Python代码如下(Python 3.8)
from skimage import io, metrics
original_image = io.imread('Original(144 KB).png')
compressed_image = io.imread('Compressed (39 KB).png')
value = metrics.structural_similarity(original_image, compressed_image, multichannel=True)
print('ssim value: %f'%value)
然而求出的相似程度居然只有69%,让我对结果产生怀疑。仔细研究一番后发现某些像素点的RGB值在压缩之后产生了非常巨大的变化。Alpha等于零的像素,无论它的RGB值是多少,该像素最终都不可见。据此推断,压缩算法利用这个特点,在Alpha等于零的情况下大幅调整RGB以进一步对图像进行压缩
因此,进行图片相似度评价之前,应该将RGB值预先乘以Alpha值,调整后的代码如下
from skimage import io, metrics
def premultiply_alpha(image):
height = image.shape[0]
width = image.shape[1]
for y in range(height):
for x in range(width):
pixel = image[y, x]
alpha = pixel[3]
factor = alpha / 255
image[y, x, 0] *= factor # Red
image[y, x, 1] *= factor # Green
image[y, x, 2] *= factor # Blue
original_image = io.imread('Original(144 KB).png')
compressed_image = io.imread('Compressed (39 KB).png')
premultiply_alpha(original_image)
premultiply_alpha(compressed_image)
value = metrics.structural_similarity(original_image, compressed_image, multichannel=True)
print('ssim value: %f' % value)
最终得到图片压缩前后的相似性是98%
结论
回答标题的问题,PNG格式不支持Premultiplied Alpha原因(不一定准确)
- 对PNG格式而言,(0, 0, 0, 0) 与 (100, 100, 100, 0)没有区别,因为它们最终都不可见
- 对Premultiplied Alpha而言,RGB值需要预先乘以Alpha,因此(100, 100, 100, 0)是不存在的像素,因为RGB在乘以0之后不可能还是100