Pillow调用alpha_composite合成图像后输出PNG体积过大优化方案
问题原因
文件体积暴涨不是代码错误,是图片格式特性导致的:
- 原
image0是8MB的JPG文件,属于有损压缩格式,压缩率极高,适合存储自然拍摄的照片类内容; - 将图片转为RGBA模式后保存为PNG格式,PNG是无损压缩格式,对于照片类内容,同分辨率下无损PNG的体积本来就是高质量JPG的5~10倍,4.3KB的叠加层对最终体积影响极小。
之前写的缩放到20%的代码语法没有问题,画质差主要有两个原因:
- Pillow旧版本
resize方法默认使用NEAREST(最近邻)插值,缩图时会产生明显锯齿、模糊; - 直接缩到原尺寸的20%意味着总像素量只有原图的4%,分辨率损失过大,自然会有明显的画质下降,不适合作为延时视频的素材。
优化方案
按优先级从高到低推荐,都可以做到几乎无肉眼可见画质损失的前提下大幅缩小文件体积:
方案1:直接保存为高质量JPG(最优,适配视频制作场景)
后续用FFMPEG制作延时视频时,视频帧本身不需要支持透明通道,完全没必要保留RGBA格式存PNG。合成后转回RGB模式保存为高质量JPG即可,体积基本和原JPG持平,肉眼几乎看不出画质差异。
result = Image.alpha_composite(image0, image1) # 转回RGB模式移除alpha通道 result = result.convert("RGB") result.save( outfile, format="JPEG", quality=92, # 90~95区间画质和原图几乎无差,可根据需求微调 optimize=True, subsampling=0 # 关闭色度子采样,避免叠加的文字/线条边缘发糊 )
这个方案通常可以把输出文件体积从2343MB降到510MB,压缩率最高。
方案2:必须保留透明通道时,使用PNG最高无损压缩
如果业务场景必须保留PNG的透明通道,可以调整Pillow保存PNG的压缩参数,全程无损不损失画质,只是保存时的计算量稍高,对每分钟执行一次的频率完全没有压力。
result = Image.alpha_composite(image0, image1) result.save( outfile, format="PNG", compress_level=9, # 最高级无损压缩,默认值为6 optimize=True )
该方案可以在不损失任何画质的前提下,比默认参数的PNG输出小20%~40%,但体积仍然会明显大于高质量JPG。
方案3:确需降分辨率时,使用高质量重采样算法
如果确实需要降低素材分辨率,不要使用默认插值算法,改用LANCZOS重采样(缩图场景下画质最好的插值算法),同时不要把缩放比例设得过低(建议不低于原尺寸的70%),就能在缩容的同时保留足够细节。
# 示例:缩到原尺寸的80%,可按需调整比例 scale = 0.8 target_size = (round(result.size[0]*scale), round(result.size[1]*scale)) # 注意:Pillow 9.1.0以下版本用 Image.LANCZOS 替换 Image.Resampling.LANCZOS result_resized = result.resize(target_size, resample=Image.Resampling.LANCZOS)
进阶优化(适合延时视频场景)
如果追求最高处理效率,可以跳过「保存帧到本地磁盘」的步骤,直接将合成好的图像数据通过管道传给FFMPEG编码视频,能省去大量磁盘读写耗时,整体处理速度会提升数倍。
内容的提问来源于stack exchange,提问作者Codejoy
相关产品推荐
相关产品推荐

