PNG格式为何不支持Premultiplied Alpha?

本文首先叙述一段经历,然后得出结论,想看结论的可以直接跳到最后

经历

用一张带Alpha通道的PNG图片作为原始输入,然后用常用的PNG图片压缩工具pngquant处理得到压缩后的图片

Original (144 KB).png
Compressed (39 KB).png

(图片来源: 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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容