使用 FFmpeg 处理高质量 GIF 图片(2)

第一遍是对整个图片计算一个调色板,这就是新的滤波器参与进来的地方。这个滤波器对每一帧的所有颜色制作一个直方图,并且基于这些生成一个调色板。

在技术层面上还存在一些琐事:这个滤波器实现了Paul Heckbert的这篇Color Image Quantization for Frame Buffer
Display (1982)论文中的算法的一个变种。这里是我记得的一些不同之处(或者说是关于论文中未定义的行为的特异性):

它使用一个全解析度的色彩直方图。而不是论文中作为关键建议使用的下采样 RGB 5:5:5 直方图,这个滤波器对1600万种可能的 RGB 8:8:8 色彩使用了一个哈希表。

对方格的分割任然是在中点上进行的,对要分割的方格的选择是根据方格中的颜色方差来进行的(一个带有大的色彩方差的方格将会优先截掉)。

对方格中的颜色求平均值取决于颜色的重要性,就我而言,这在论文中并没有定义。

当沿着一个维度(红,绿或蓝)进行分割方格时,假如相等,绿色是优先于红色的,然后再是蓝色。

所以不管怎样,这个滤波器都是在做色彩量化,并且生成一个调色板(通常保存在一个PNG文件里)。

它通常看起来像这个样子(upscaled):

centerimg

颜色映射与抖动

第二遍(验码)是通过滤波器完成的,就跟它的名字一样,它将会使用这个调色板来生成最终的量化颜色流,它的任务是在生成的调色板中找出最合适的颜色来表示输入的颜色。这也是你可以选择使用哪种抖动方法的地方。

这里同样有一些技术侧面上的小问题:

使用这两个滤波器可以让你将GIF编码成这样(单全局调色板,无抖动):

centerimg

用法

使用相同参量手动运行两遍(验码)是有点讨厌,还要对每一遍的参数进行调整。所以我推荐写一个简单的脚本,如下:

#!/bin/sh palette="/tmp/palette.png" filters="fps=15,scale=320:-1:flags=lanczos" ffmpeg -v warning -i $1 -vf "$filters,palettegen" -y $palette ffmpeg -v warning -i $1 -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y $2

…可以这样使用:

% ./gifenc.sh video.mkv anim.gif

filters变量包括:

一个帧率的调整(减小到15会使画面看起来不平稳,但可以使最终的GIF体积更小)

一个取代默认(目前是bilinear)定标器的lanczos定标器缩放比例。推荐它的原因是你使用lanczos或bicubic来缩放画面要比bilinear优越的多。如果你不这样做的话,你的输入会模糊的多。

提取:仅作示例

不见得你会编码一部完整的影片,所以你可能会对使用-ss和-t选项来选择一个片段感兴趣。如果你真是这样,那么就要确保将它作为输入选项加入(在-i选项之前),例如:

#!/bin/sh start_time=12:23 duration=35 palette="/tmp/palette.png" filters="fps=15,scale=320:-1:flags=lanczos" ffmpeg -v warning -ss $start_time -t $duration -i $1 -vf "$filters,palettegen" -y $palette ffmpeg -v warning -ss $start_time -t $duration -i $1 -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y $2

如果不是,那么至少在第一遍它就会导致没有多个帧输出(调色板),所以不会做你想要的。

一个可供选择的是在流复制中预提取你想要编码的片段,看起来是这样:

% ffmpeg -ss 12:23 -t 35 -i full.mkv -c:v copy -map 0:v -y video.mkv

如果流复制不够精确,你可以添加一个滤波器。例如:

filters="trim=start_frame=12:end_frame=431,fps=15,scale=320:-1:flags=lanczos" 获得最好的调色板输出Getting the best out of the palette generation

现在我们可以开始看有趣的一部分了,在palettegen滤波器中,主要的和能让你感兴趣去尝试的大概就是stats_mode选项了。

这个选项的主要作用就是允许你指明在整部视频中你需要东西,或者只是移动的物体。如果你使用stats_mode=full(默认),所有的像素将会是颜色统计的一部分。如果你使用stats_mode=diff,只有与前一帧不同的像素会被计入。

注意:向一个滤波器中添加选项,需要这样做:filter=opt1=value1:opt2=value2

下面是一个例子来说明它是怎样影响最终的输出的:

centerimg

centerimg

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/3d5cf9575bce8fc85ab4f733c66e169c.html