多次重新压缩JPEG时,哪些因素会导致或防止“世代丢失”?


29

多年以来,我一直认为多次压缩JPEG文件会逐渐降低其质量,直到它们变得无法识别为止,就像影印本一样。从直觉上讲这是有道理的,因为JPEG是有损格式。还有其他一些问答,也是如此:

但是,我还读到,以相同的质量级别重新压缩JPEG 不会降低图像质量。这与其他地方所述的逐步退化背道而驰。

JPEG重新压缩后,技术上会发生什么? 什么丢失了,如何丢失?图像真的会变成电视上经常出现的白雪皑皑的混乱吗?这些视频显示的图像在多次重新压缩后会崩溃吗?

(请不要随便挥手并诉诸有损的一般概念。)

(这个问题,到目前为止,它已经吸引了答案,专注于技术因素(具体设置和图像操作),其原因或防止图像退化时,JPEG文件进行再压缩多个次)。





2
@MonkeyZeus 质量为100时,由于舍入错误而丢失了一些(少量)图像数据。以相同设置(例如80)重新压缩不会导致渐进的数据丢失。这就是该问答旨在解决的“常识”。
xiota

1
@MonkeyZeus诸如“ 100”和“ 80”(或在Photoshop中为“ 10、11、12”)之类的值是任意的-100%并非无损。
mattdm

Answers:


32

几乎所有图像质量损失都是在图像第一次压缩为JPEG时发生的。不管使用相同设置将JPEG重新压缩多少次,代损失都限于舍入误差。

  • MCU边界保持不变(8x8块)。

  • 色度二次采样已禁用。

  • 恒定DQT(相同的质量设置)。

但是,对于不满足上述条件的每次迭代,舍入误差可能会很大因此,请谨慎保留所有原始文件的备份。


JPEG压缩算法

  1. 转换色彩空间。如果需要,请对颜色信息进行下采样(色度二次采样)(有损)。如果不进行降采样,则信息丢失是舍入误差的结果。

  2. 分割。将每个通道划分为8x8块(MCU =最小编码单位)。 (无损)

    注意:如果启用了色度二次采样,就原始图像而言,MCU实际上可能是16x8、8x16或16x16。但是,MCU仍然都是8x8块。

  3. 每个MCU上的离散余弦变换(DCT)。信息丢失是舍入误差的结果。

  4. 量化。 MCU的每个单元中的值除以量化表(DQT)中指定的数字。值四舍五入,其中许多将变为零。 这是算法的主要有损部分。

  5. 之字形扫描。按照锯齿形将每个MCU中的值重新排列为数字序列。量化期间发生的零将被分组在一起。 (无损)

  6. DPCM =差分脉冲编码调制。将数字序列转换为更易于压缩的形式。 (无损)

  7. RLE =游程长度编码。连续零被压缩。(无损)

  8. 熵/霍夫曼编码。 (无损)

重新压缩JPEG

请注意,对颜色通道进行降采样和量化是仅有的有意损耗步骤。暂时保留舍入错误,所有其他步骤都是无损的。量化一旦发生,反转并重复该步骤即可得到相同的结果。换句话说,重新量化(使用相同的DQT)是无损的

原则上,可以创建在第一次通过后无损失的重采样算法。但是,通过ImageMagick的实现,颜色可能会在达到稳定状态之前急剧变化,如该图所示。

在最佳条件下,以相同的质量设置重新压缩JPEG将得到完全相同的JPEG。换句话说,重新压缩JPEG 可能无损。实际上,重新压缩JPEG不是无损的,而是受舍入误差的限制。尽管舍入误差通常最终会收敛到零,以便重新创建完全相同的图像,但是色度二次采样可能会导致颜色发生重大变化。

演示(相同的质量设置)

我编写了以下bash脚本,该脚本使用ImageMagick以给定的质量设置重复地重新压缩JPEG文件:

#!/usr/bin/env bash
n=10001; q1=90
convert original.png -sampling-factor 4:4:4 -quality ${q1} ${n}.jpg

while true ; do
   q2=${q1}            # for variants, such as adding randomness
   convert ${n}.jpg -quality ${q2} $((n+1)).jpg
   #\rm $((n-5)).jpg   # uncomment to avoid running out of space
   n=$((n+1))

   echo -n "$q2  "
   md5sum ${n}.jpg
done

让它运行数百次迭代后,我运行md5sum了结果:

d9c0d55ee5c8b5408f7e50f8ebc1010e  original.jpg

880db8f146db87d293def674c6845007  10316.jpg
880db8f146db87d293def674c6845007  10317.jpg
880db8f146db87d293def674c6845007  10318.jpg
880db8f146db87d293def674c6845007  10319.jpg
880db8f146db87d293def674c6845007  10320.jpg

我们可以看到,确实,舍入误差已收敛到零,并且一遍又一遍地复制了完全相同的图像

我已经用不同的图像和质量设置重复了多次。通常,会达到稳定状态,并且一遍又一遍地复制完全相同的图像。

怎么样@ mattdm的结果

我试图在Ubuntu 18.04上使用Imagemagick复制mattdm的结果。最初是在Rawtherapee中原始转换为TIFF,但似乎不再可用。取而代之的是,我采用了放大版本并将其缩小为原始尺寸(256x256)。然后我在75处重复压缩,直到收敛为止。这是结果(原始,1,n,差):

尝试复制mattdm

我的结果是不同的。没有真实的原件,差异的原因无法确定。

@ths的蒙太奇呢?

我从蒙太奇的左上角重新压缩图像,直到在90处收敛。这是结果(原始,1,n,差):

尝试复制蒙太奇

启用色度二次采样后,颜色会在达到稳定状态时发生变化

色移

在少数设置之间进行更改

通过修改变量q2,可以将质量设置限制为一组均匀分布的值。

q2=$(( (RANDOM % 3)*5  + 70 ))

对于少数设置选项,最终可能会达到平衡,这是在md5值开始重复出现时看到的。在达到平衡之前,设置似乎越大,花费的时间越长,并且图像变得越差。

平衡时似乎发生的事情是,量化之前的DCT系数必须被所有(或大部分)量子值整除。例如,如果在DCT系数被3和5交替除的两个DQT之间切换,则DCT系数被15除时将达到平衡。这解释了为什么质量下降远大于原始设置之间的差异。

在大量设置中进行更改

q2像这样改变时,Eeyore不高兴:

q2=$(( (RANDOM % 9)  + 90 ))

要制作视频,请使用ffmpeg

rename 's@1@@' 1*.jpg
ffmpeg -r 30 -i %04d.jpg -c:v libx264 -crf 1 -vf fps=25 -pix_fmt yuv420p output.mp4

观看前9999次迭代几乎就像观看水沸腾一样。可能希望将播放速度提高一倍。这是11999年迭代后的Eeyore:

11999年迭代,随机DQT

如果MCU边界发生变化怎么办?

如果更改发生的次数有限,则反复进行重新压缩很可能会达到稳定状态。如果在每次迭代中发生更改,则图像可能会以与DQT更改时类似的方式降级。

那编辑呢?

编辑后重新压缩的效果取决于执行的特定编辑。例如,减少JPEG伪像后以相同的质量设置进行保存将重新引入相同的伪像。但是,应用局部变化(例如修复刷)不会影响未被触摸的区域。

图像质量的最大下降发生在第一次以给定的质量设置压缩文件时。随后使用相同的设置进行重新压缩不应引起大于舍入误差的变化。因此,我希望在给定的质量设置下,编辑-重新保存周期看起来像保存了相同质量设置的任何其他图像一样(只要MCU边界保持不变且色度二次采样被禁用)。

那些视频呢?

我可以用重新压缩的JPEG覆盖原稿吗?

保留所有原始文件的备份是谨慎的做法,但是如果您不小心覆盖了一个原始文件,则损坏可能会受到限制。在禁用色度二次采样的情况下在JPEG中工作也很好

JPEG不能用于每种颜色使用8位以上的图像。


5
但是,图片与load- edit -save循环完全不同。在这种情况下,重复量化将导致性能下降。
ths

2
我只是用与答案相同的脚本进行了测试。这是tp 100上每20张图像的蒙太奇图像:i.stack.imgur.com/xtob6.jpg非常重要。
18th

2
啊。发现我的图片有问题。如果打开了色度二次采样,则会导致渐进降级。
18th

2
也发现了。因此,启用色度二次采样会在达到稳定状态之前显着改变图像中的颜色。
xiota

2
使用完全相同的参数重复进行加载和保存不会造成无限的质量损失,因为大多数输入文件都可以加载和重新保存而不会引入其他舍入错误,并且可能会受到舍入错误影响的文件可能会转换为不会的文件。另一方面,重复的加载/保存周期在相似但不相同的压缩参数之间交替,可能导致每个周期的舍入误差。
超级猫

20

重新压缩损失是真实的,尤其是在使用更高级别的JPEG压缩时。

从理论上讲,如果您使用完全相同的参数重新保存JPEG文件并将裁切对齐为8×8块,则降级应该很小。但是,如果您使用的是高级别的压缩,您会发现进一步的损失,因为初始压缩引入的像是图像的永久更改,并且也会被重新压缩,从而导致更多的伪像。

如果以较低的压缩级别(高质量,例如Gimp中的“ 100”或Photoshop中的11或12)重新保存,则任何新添加的工件都将很难被注意到。它不会使图像变,但不会明显变差。然而,推出在整个图像的变化。

作为一项快速测试,我使用ImageMagick以75%的速率反复压缩JPEG图像。下面的示例作为PNG文件上传,以避免进一步压缩,并且在我转换为PNG时将其大小加倍,以使效果更加明显。(测试中使用的原始文件未加倍。)事实证明,经过八次重新采样后,效果收敛到了一个完美稳定的结果,在此情况下再次重新压缩会生成逐位相同的文件。

这是未压缩的原件:

原始,无jpeg压缩

将结果转换为75%JPEG的结果如下:

第一个jpeg

并重新保存了以下内容:

第二遍

一秒钟的节省会导致大量额外的降级!

这是最终的融合图像(第8遍):

融合jpeg

同样,颜色肯定还差得多,包括一些错误的颜色图案,而块状伪像跳出的次数更多。该算法收敛,但版本明显降低。所以,不要那样做。

但是,经过9次通过之后,质量水平为99%的东西是相同的(收敛的点,因此进一步的通过是相同的):

99%9次

在这里,差异几乎不存在。(我的意思是,逐个像素地将它们与非压缩版本进行比较,并且偏差只是很小的随机噪声。)那么,如果我回到第一个75%的图像然后以99%的分辨率重新保存,该怎么办?好吧,这(仅一次):

一次75%,然后一次99%

明显地,高质量保存显然比具有相同参数的保存更好,这令我惊讶。但是,粉红色饰边和眼睛周围明显有新的退化。使用相同设置的回收版,每次重新压缩都会夸大JPEG伪像。由于我选择了低分辨率和低质量,事实证明,这比以不同方式重新压缩所有内容要差。

在这些视频上:我发现这是 Google的热门歌曲。注意它在描述中说:

如果您在随机高质量设置(85或更高)下多次重新编码JPEG图像,就会发生这种情况。

添加重点 -这说明了为什么没有任何收敛的原因,因为每次都使用随机设置,而不是使用相同的设置保存或以超高质量保存。

我发现第二个视频说:

复制JPEG图像,并为每个图像旋转一整圈。[...](596个“顺时针旋转”动作)

因此,再次进行了一些操作以使错误不断累积。

在任何情况下,实际照片编辑,值得一提的是,节省75%的一次是比在99%重新保存一个差多少百万。在我的示例案例中,人为因素在75%处非常明显,以至于进一步的退化就像在大海中倾倒水一样。如果您以足够高的级别保存了这些工件,那么它们实际上是不可见的,那么使用原始设置再次保存是一个不错的策略。当然,如果您可以始终使用未压缩的原稿,那将是更好的选择。

如果出于某种原因您必须(或强烈希望)仅使用JPEG,请将相机设置为尽可能以最高的质量保存,即使您没有注意到初始文件中的差异也是如此。请参阅使用Pentax的Premium JPEG质量设置值得吗?有关更多信息-不一定确实是Pentax专用的。


(1)您节省了75%。在该设置下,可能会损失图像质量。(2)选择并更改该图像以夸大JPEG压缩伪像。(3)经过8轮压缩后图像会聚,此后图像质量不会进一步降低。(4)该图像的视频显示“世代损失”,在最初的1/4秒之后,几乎什么也没有发生。
xiota

5
(1)是的。(2)“精选”为典型的照片,人们可能会在意这种事情。“更改”仅用于放大。请注意,这仅用于此处显示 -我没有将正在处理的图像的大小加倍。(3)是的,但是在实践中,这是您可能需要注意的前几轮。(4)是的,但这并不意味着收敛到最坏的情况并停留在任何地方都是有用的。
mattdm

若要复制,请拍摄第一张图像并调整为256×256,而无需任何重新采样或插值。
mattdm

我不能看到多少你显示的图像之间的差异。但是,如果我拿的单,再压缩和mutliply,再压缩图像的差异,放大它,使其可见,我得到这个(更令人信服的)结果:i.stack.imgur.com/57uaY.png (见我删除确切执行操作的答案),这更具说服力,因为人们不必一直盯着图像来检测微小的差异。
Szabolcs

差异很小。如果您有一个大的LCD屏幕,则由于视角略有不同而导致的不同“伽玛”值会使伪像显得更加突出。
xiota

5

重新压缩确实对图像质量有可测量的影响,并且在更改压缩率时这种影响更加明显。

在此可以快速查看一些SSIM值,以对包含线要素和连续要素的测试图像执行的操作。我之所以选择JPG95,是因为这是我在广告学院学习的方法,而选择JPG83是因为在数字内容提供商中这是很常见的。

  • 将Tiff图片另存为JPG95-.9989
  • 将Tiff图片另存为JPG83-.9929
  • 将JPG95图像另存为JPG95 10次-.9998
  • 将JPG83图像另存为JPG83 10次-.9993
  • 将JPG95重新保存为JPG83,然后重新保存为JPG95-.9929
  • 将JPG95重新保存为JPG83,然后将JP83重新保存为JP92,然后将JPG92重新保存为JPG86-.9914

因此,以相同压缩率保存10次所丢失的结构相似性数量,是以tiff的质量保存时所失去的结构相似性的1/10。但是,即使更改一次JPG压缩所导致的质量损失与将图像从Tiff保存到JPG所损失的质量相同。

我将以其他几种方式运行此测试并进行更新。

方法:在ImageJ中:

  1. 将Tiff RGB转换为灰度8位
  2. 从Tiff Original保存JPG95和JPG83
  3. 按照指定进行进一步的重新保存操作
  4. 加载比较图像并使用SSIM索引插件

注意:许多人第一次查看SSIM值时,会以百分比形式读取它们,并认为差异很小。这不一定是真的。SSIM值应相互比较,而不是与1的差异。


@xiota,我正在为ImageJ使用SSIM插件。这是少数可以调整参数的SSIM实现之一(我将滤镜宽度设置为8,这样它就更有可能检测到16px JPEG块内的变化。)我更喜欢SSIM,因为它对能量差异更加敏感重新分配。如果差异被抵消或差异集中在较小区域中,则差异图像可能会产生误导。
PhotoScientist

关于第二个问题,就是说从JPG95到JPG83到JPG95的区别与从Tiff到JPG83的区别是相同的。如果您想要Tiff-JPG95-JPG83-JPG95,则为.9923
PhotoScientist

尝试了四种不同的压缩方式。损失仍然更大,但是很显然,在尝试多个不同的压缩时,在同一压缩的几代中都看到了“收敛”。仍然想在以应用程序为中心的工作流程中尝试此操作,但这需要更多的工作量。
PhotoScientist

另一个问题是,没有“质量”设置到SSIM阈值的标准映射,也没有任何方法可以确定需要什么质量设置来避免大量信息丢失。如果加载JPEG并将其保存在足够高的设置下,则可以避免其他质量损失,但文件可能会变大。如果不知道在生成文件时使用了什么设置,则可能很难确定在重新保存文件时使用什么设置。
超级猫

4

没有什么像实验。以下bash脚本(在Linux上编写,如果您具有ImageMagick,则可以在OSX上运行):

  • 从第一个图片(名为step000.jpg)开始
  • 拍摄一个JPEG文件,添加一个白点(以证明这是新图像)并将其另存为(无损PNG)
  • 接收PNG,然后将其重新压缩为JPEG(因此,我们从不将JPEG压缩为JPEG,也不能假设该软件只是复制编码的块)
  • 使图像显示两个JPEG之间的不同像素
  • 使用上一步的输出JPG冲洗并重复

结果是:

  1. 高JPG品质不会造成太大损失
  2. 舍入错误最终解决了,经过几代人的努力,事情不再恶化。

当然,所有这些都假定JPEG每次都是由相同的软件使用相同的参数保存的。

#! /bin/bash
# Runs successive JPEG saves on an image to evaluate JPEG losses

# convert & compare command from imagemagick
# if you use a recent version of IM, set these variables to:
# compare="magick compare"
# convert="magick convert"
convert=convert
compare=compare

dotradius=2
defaultsteps=10
defaultquality=90 # default quality for "convert"

function usage {
        echo "Usage: $0 [quality [steps]]"
        echo ""
        echo "Where:"
        echo "       - 'quality' is the quality factor of the JPEG compression "
        echo "          (1-100, 100 is best, default is $defaultquality)"
        echo "       - 'steps' is the number of successive steps to perform"
        echo "         (default is $defaultsteps)"
        echo ""
        echo "Produces:"
        echo "   - successive saves of a JPEG image to test JPEG-induced losses."
        echo "   - compare images with the original file and the 1st JPEG save."
        echo ""
        echo "Starts from a 'step000.jpg' file in the current directory."
        exit 1
}

[[ -n "$3" ]] && { usage ; exit 1 ; }
steps=${1:-$defaultsteps}
quality=${2:-$defaultquality}    
dotcolor="white" # change this if the top of the image is too clear

echo "Running with $steps steps with quality $quality"

for step in $(seq $steps)
do 
    echo "Step $step of $steps"
    src=$(printf step%03d $(( $step - 1 )) ) 
    dst=$(printf step%03d $(( $step )) )
    dif=$(printf diff%03d $(( $step )) )
    # dot coordinates
    let cxc="2 * $dotradius * $step"
    let cxr="$cxc + $dotradius"
    let cyc="$dotradius * 2"
    let cyr="$dotsradius * 2"

    $convert $src.jpg -fill white -draw "circle $cxc,$cyc,$cxr,$cyr" $dst.png
    $convert $dst.png -quality $quality $dst.jpg
    rm $dst.png
    $compare $src.jpg $dst.jpg $dif.jpg
done

目前暂时不显示结果,我希望您尝试自己的照片。有足够的评论,我将添加一个示例。


1
我对不同的软件感到好奇。我尝试从7种不同的软件中保存7倍。差异很大,因此我将其分解以查看每个应用程序是否具有相同的损失。其中1个应用负责所有变化。一旦我删除了红色鲱鱼,从6x程序中进行的6x保存就与从ImageJ中进行6x的保存相同
PhotoScientist

可能是某些编码错误的软件。混用来自各种应用程序的算法也可能会防止舍入错误解决。
xenoid

@xiota,这是一个奇怪的小程序,名为FLEMinimizer。我什至不记得为什么我一开始就拥有它。其他的是ImageJ,Matlab,Photoshop,FastStone Image Viewer,Ifranview和CameraRaw。这六个之间的任何步骤几乎没有变化。
PhotoScientist
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.