ImageMagick 示例 -
视频处理

索引
ImageMagick 示例前言和索引
视频转 GIF,优化总结
去隔行视频帧
ImageMagick 不太适合处理数字视频,但它通常用于此目的,尤其是在 Linux 环境中。在这里,我将探讨专门针对处理真实世界(和光线追踪)视频序列的技术和示例。

视频转 GIF,优化总结

一位使用 IM 创建电影 GIF 的软件开发人员,Benoit Rouleau,在与我的讨论中,给了我一个关于 飞机飞过 的 AVI 视频,帮助我们相互探索 IM 视频转换技术。然而,虽然 AVI 本身非常小,但未压缩的视频是一个巨大的 [IM 文本] 字节大小,并且包含 [IM 文本] 种颜色,超过 [IM 文本] 帧。
然而,IM 在将此视频转换为 GIF 动画方面没有真正的问题。但是请注意,您可能会遇到一些不受支持的“AVI 块”错误,可以使用“-quiet控制设置忽略这些错误。

  magick -quiet -delay 1 plane.avi plane.gif
[IM Output]
这使用 ImageMagick 的默认 颜色量化和抖动 方法,以生成视频的非常合理的转换。颜色问题很少,因为视频一开始使用的颜色很少。情况并非总是如此,尤其是在 GIF 每帧颜色限制为 256 色的情况下。但是,动画文件的大小为 [IM 文本] 字节,虽然由于颜色减少和 GIF 像素数据压缩,它只有原始大小的 1/5,但它仍然相当大。此外,如果您进一步研究生成的动画,您会发现 [IM 文本] 帧图像中,[IM 文本] 帧添加了它们自己的 局部颜色表。也就是说,GIF 动画中的每一帧都需要自己的颜色索引表。也就是说,虽然每帧的颜色少于 256 色(由于 GIF 格式的限制),但整个动画使用的颜色总数为 [IM 文本] 种。不幸的是,GIF 格式不压缩颜色表,因此所有这些额外的颜色表可能使用多达:  256 色 * 每色 3 字节 * 106 帧;  或者 81,408 字节的文件空间。对于 1G 字节的视频来说不算多,但仍然是相当可观的,尤其是在我们进一步优化视频时。除此之外,动画不会很好地优化 GIF 帧。不仅因为背景正在移动(由于摄像机向上平移),而且因为 IM 使用了 误差修正抖动(希尔伯特曲线抖动),它产生了一种伪随机颜色模式,该模式帧与帧之间不同。后面的示例将使这种“抖动噪声”更加明显。

公共全局颜色表

在这里,我为视频的所有帧生成一个单一的全局颜色表

  magick -quiet -delay 1 plane.avi  +remap   plane_cgc.gif
这自然会导致 [IM 文本] 局部颜色表,以及 [IM 文本] 字节的文件大小。
[IM Output]
如您所见,生成的动画没有额外的局部颜色表。相反,IM 生成了一个 [IM 文本] 个“最佳”颜色的全局颜色表,这些颜色基于动画中的所有帧。不幸的是,这也导致像素数据没有像以前那样压缩得很好,因为需要更强的抖动。结果是一个看起来略差的动画,它的尺寸与之前的动画大致相同。对于这种特定颜色有限的视频,我甚至可以将使用的颜色数量进一步减少到 64 色,而不会出现太多问题,从而生成一个更小的动画文件大小。但是,这非常依赖于使用的视频序列,并且可能看起来不太好。您自己的视频可能会有更好的结果或更差的结果,尤其是在处理使用更多颜色并且可能包含多个场景的视频时。

通用全局颜色表

生成“更小”的 GIF 动画的更好方法是只提供一个通用的颜色范围,而不是为动画生成“最佳”的全局颜色表。使用一个应该在原始视频中存在任何颜色时都能很好地工作的颜色表。这样做的另一个原因是,您可以使您的视频更长,而不会对颜色选择产生严重的不利影响,或者需要为每帧使用局部颜色表。每帧都抖动到同一个颜色映射,完全独立于动画中存在哪些其他帧。
在这里,我使用一个 '332' 颜色映射,它通常被认为是在不需要透明度时非常好的标准颜色映射。我经常看到这种颜色映射(或一个 219 色的 '网络安全' 颜色映射)在各种视频格式中使用。

  magick -quiet -delay 1 plane.avi -remap colormap_332.png plane_ugc.gif
[IM Output]
此动画有 [IM 文本] 个局部颜色表,因此动画更小,大小为 [IM 文本] 字节。然而,问题是您经常会在恒定颜色区域看到明显的恼人的“噪声”。这种噪声也存在于之前的所有视频动画中。它只是现在可见,因为使用了更通用的,因此更广泛分布的颜色映射。噪声实际上是由生成图像时减少的颜色集的抖动引起的。但是,这会产生一个伪随机的颜色模式,该模式帧与帧之间不同,导致图像中出现背景噪声。有关发生这种情况的原因的更多详细信息,请参阅 E-Dithers 的问题
我们可以直接关闭颜色抖动以消除“抖动噪声”...

  magick -quiet -delay 1 plane.avi \
          +dither -remap colormap_332.png plane_ugc_nd.gif
它有 [IM 文本] 个局部颜色表,大小为 [IM 文本] 字节。
[IM Output]
生成的动画非常小,只有原始动画的 1/60,通常是因为大面积的纯色产生了极好的像素压缩。但是,虽然它修复了抖动噪声,并且使文件大小非常小,但您会看到色带,这通常被认为是一个非常糟糕的权衡。

有序抖动视频

真正的解决方案是使用不同的颜色抖动技术,该技术不会在一帧到下一帧之间产生不同的模式。
例如,在这里我使用 使用分色颜色级别的有序抖动 来抖动同一个通用的 '332' 颜色映射

  magick -quiet -delay 1 plane.avi \
          -ordered-dither o8x8,8,8,4 +remap plane_od.gif
它有 [IM 文本] 个局部颜色表,大小为 [IM 文本] 字节。
[IM Output]
上面还使用了“+remap”运算符,以确保所有图像使用完全相同的全局颜色映射(有序抖动已将其减少到最多 256 色)。由于颜色数量已经是最佳的,因此“+remap”运算符不进行抖动或颜色减少。生成的抖动模式不是随机的,并且帧与帧之间不会发生太大变化。因此,“抖动噪声”已从动画中移除,从而在帧与帧之间产生了固定的颜色模式。该模式也非常重复,允许更好的压缩。最后,由于颜色映射是固定的,因此它应该在使用任何视频时都能很好地工作。

更高质量的有序抖动视频

然而,此特定视频只使用了一小部分颜色,主要是各种蓝色阴影,因此它实际上并没有使用通用统一颜色映射提供的很多颜色。事实上,上一个视频动画中只使用了 [IM 文本] 种颜色!这非常低,因此也相当明显。但这也意味着这种特定动画可以从在有序抖动操作中使用大量“颜色级别”中获益,从而提高整体质量。然而,首先我们需要确定动画在达到 GIF 文件格式和全局颜色映射重新映射所施加的 256 色限制之前可以处理多少颜色级别。然而,棘手的部分是您必须在将动画保存到有限的 GIF 格式之前确定这些级别。以下是我使用的命令...

    magick -quiet plane.avi -ordered-dither o8x8,23 -append -format %k info:
[IM Text]
基本上,我增加和减少要使用的颜色级别数,直到我得到一个正好在所需的 256 色限制内的数字。
然后,我可以将发现的“颜色级别”选择应用于飞机动画。

  magick -quiet -delay 1 plane.avi \
          -ordered-dither o8x8,23 +remap plane_od2.gif
它有 [IM 文本] 个局部颜色表,大小为 [IM 文本] 字节,并且使用了 [IM 文本] 种颜色。
[IM Output]
如您所见,生成了一个非常高质量的有序抖动视频,它与我们之前生成的“最佳颜色映射”全局颜色映射版本相当,但大小也只有它的 1/3,而“抖动噪声”现在更难看到。当然,由于质量如此之高,它确实需要更大的文件大小,因为它不像低质量版本那样压缩得很好。另一方面,您现在实际上可以以“颜色级别”数量的形式很好地控制质量与文件大小之间的权衡。请记住,此技术是一个特殊情况,适用于不使用太多颜色的动画。通过添加更多帧来使视频更长也会添加更多颜色,因此需要降低“颜色级别”质量控制。这是我见过的用于一般 GIF 动画的最佳颜色优化方法。它消除了“抖动噪声”,提供了一些质量控制,并保留了使用其他 GIF 动画优化方法的能力,例如 帧优化

压缩(透明度)优化

因为此视频使用了平移摄像机,所以视频的背景帧与帧之间不同。这意味着 GIF 动画将无法很好地 帧优化
但是,我们仍然可以使用简单的 透明度优化 来进一步减小最终的 GIF 动画大小。

  magick plane_od2.gif  -layers OptimizeTransparency +remap plane_opt.gif
结果大小为 [IM 文本] 字节,并且使用了 [IM 文本] 种颜色。
[IM Output]
也就是说,图像中添加了一种额外的颜色,一个透明的颜色索引,并且任何不改变当前显示颜色的像素都被设置为透明。这反过来会在原始动画中生成大片的透明区域,以及重复的类似像素序列,这会在最终的 GIF 图像中生成改进的 LZW 压缩。还不错,动画现在只有直接转换为 GIF 的一半大小,而且质量仍然相当高。如果您想对此进行补充,讨论进一步改进的技术,请联系我或 IM 论坛。我很乐意听取您的意见、技术和讨论,或者查看您可能遇到的特定视频/动画问题。 其中一个讨论是 为动画 GIF 量化找到“合适的级别”

Giflossy 压缩 LZW 优化

一个新的工具,GifLossy,它是原始 Gifsicle 程序的衍生版本,它修改了每帧的颜色,以便 LZW 可以更好地压缩图像。
例如,我将其应用于原始的 GIF 动画,要求它将颜色减少到单个 256 色表。

  gifsicle -O3 --lossy=80 --colors 256 plane.gif -o plane_giflossy.gif
这有绝对惊人的大小,[IM 文本] 字节。它的质量远不及我们使用有序抖动所达到的质量,但它的大小不到一半。
[IM Output]
受以上结果的鼓舞,我决定在获得的最佳有序抖动结果上使用 GifLossy,看看它是否可以使它更小。

  gifsicle -O3 --lossy=80 plane_od2.gif -o plane_od2_giflossy.gif
我们确实得到了更小的尺寸,[IM 文本] 字节。不幸的是,我们基本上失去了之前如此努力才获得的高质量有序抖动结果。这令人失望。
[IM Output]


对视频帧进行隔行扫描

并非所有图像都来自数码相机。从非 CCD 视频摄像机的数字视频流中提取图像非常常见。这些图像被隔行扫描以直接在电视上显示,导致每隔一行是图像的不同帧(隔行扫描)。对于物体没有移动的两帧,隔行扫描通常不太明显。也许只会产生图像的轻微边缘模糊。但是当涉及快速移动的物体时,得到的隔行扫描图像会非常令人不安,因为两帧被合并在一起。
Wolfgang Hugemann <Auto@Hugemann.de>(德国),遇到了这个问题,并将 碰撞测试 的快照发送给了我,这是 Wolfgang 自己拍摄的。但为了演示,我将使用从这张图片中裁剪的较小图片。但是这些技术可以应用于全尺寸图片。

    magick video_frame.png  -crop 100x100+200+470 +repage  interlaced.png
[IM Output]
Wolfgang Hugemann 使用 TIFF 格式作为原始视频帧,我将其转换为 PNG 用于 IM 示例。在完成处理之前,不要试图使用 JPEG 作为这些图像,因为它会破坏此过程所需的低级质量。
如您所见,隔行扫描显示了两个独立的帧,因为它来自隔行扫描的 PAL 数字视频序列(每秒约 50 个半帧)。是的,汽车移动得非常快,而且相机使用了高速快门,产生了非常高质量的视频图像。得到的图像是在两个半帧交织在一起的图像,汽车的后视镜在半帧之间相隔的 1/50 秒时间段内移动了一段相当大的距离。
在这里,我们只需用白色替换一个隔行扫描的半帧(每隔一行)。这是标准的隔行扫描方法,称为“BoB”滤波器。这是 Wolfgang 为 IM 示例提供的。

  magick interlaced.png  -fx "floor(j/2)==j/2 ? u : 1"  deinterlace_1.png
[IM Output]
现在 FX 操作符 速度很慢,因此另一种方法是创建“条纹图像”。这种图像可以从特殊的“pattern:Horizontal2”内置图像生成。
然后可以使用“Screen”合成方法将该图像与原图叠加以叠加白线,或者使用“Multiply”叠加黑线。例如…

  magick -size 100x100 pattern:Horizontal2 \
          interlaced.png -compose Multiply -composite  deinterlace_2.png
[IM Output]
否定模式可用于选择隔行扫描图像的另一半。或者,如果将“Multiply”更改为“Screen”,则可以提取具有白色背景的帧。
作为替代方案,我尝试通过简单地复制前一行来填充缺失的帧行。

    magick interlaced.png  -fx "u.p{i,j-j%2}"  deinterlace_3.png
[IM Output]
您还可以使用 像素化技术 收缩和扩展图像,以便将每隔一行加倍。

    magick interlaced.png -sample 100%x50% \
                           -sample 100%x200%  deinterlace_4.png
[IM Output]
稍微调整一下,您就可以将两边的线条合并,以在调整大小扩展的过程中垂直平滑半帧图像。

    magick interlaced.png -sample 100%x50% \
                           -resize 100%x200%  deinterlace_5.png
[IM Output]
结果是隔行扫描视频图像的一帧的特别好的提取。
如果您想从图像中提取另一个半帧,您可以调整“sampling:offset(从 IM v6.8.4-7 开始)

    magick interlaced.png -define sample:offset=75 \
            -sample 100%x50%  -resize 100%x200%    deinterlace_6.png
[IM Output]
在 IM 的这个版本之前,您需要将图像“-roll”一个像素,才能获得相同的结果。