正文字数:3970 阅读时长:6分钟
VMAF是最受欢迎的视频质量评估工具之一,它正在成为视频行业的标准参考度量标准。但是,运行VMAF在某些情况下可能会比较棘手,并导致错误的结果。在本文中,客座作者Gabriel Davila Revelo向我们介绍了一个工具(easyVMAF),他开发的这个工具使得VMAF计算变得更加简单和直观。
作者 / Gabriel Dávila Revelo
原文链接 / https://ottverse.com/vmaf-easyvmaf/
VMAF是一个完整的参考指标,用于比较参考(或源)和失真的视频序列来预测主观视频质量。
VMAF的优势在于它试图模仿观看者的感知(或人类视觉系统),而不是纯粹的客观指标(例如PSNR或SSIM)。有关VMAF的详细说明,请阅读Netflix官方博客。
在开源社区的参与下,VMAF上已经构建了一些第三方工具。因此,可以通过几个开源软件包(例如,VMAF python库,VMAFossexec(C可执行文件),VMAF docker映像,libvmaf(C库)以及通过libvmaf编译的FFmpeg)来获得VMAF。
注意:您可以在OTTVerse.com上找到FFmpeg,VMAF的安装过程以及用法。
尽管可以使用多种工具来计算VMAF,但要遵守VMAF工具所施加的严格要求,通常是具有挑战性的。其中一些要求如下:
- 参考视频和失真视频需要进行帧同步。扫描模式(隔行/逐行)必须匹配;他们必须有相同的持续时间;它们必须具有相同的帧速率。
- 参考视频和失真视频的分辨率必须匹配,这通常需要强大的上/下缩放程序。
因此,实际上,如果参考视频和失真视频不满足上述要求,则必须对视频进行规范化/均衡处理。
在本教程中,我们将使用基于FFmpeg的示例介绍一系列建议,以向您展示如何使用VMAF标准化流。
最后,我们介绍了easyVMAF,这是一个开源工具,可以自动执行您的VMAF计算。
在接下来的几节中,我们将逐步处理(i)视频缩放的基础,(ii)帧同步,(iii)最后;我们讲谈论easyVMAF。
为了保持文章的长度合理,我们只展示一些基本的例子。要获得完整的用例,请访问:https://github.com/gdavila/easyVMAF
闲话少说,让我们开始吧!
从缩放视频的分辨率到右边的VMAF模型
现如今可用的VMAF实现支持三种模型:HD,4K和Phone。
每种模型均由Netflix的团队进行了训练,考虑了不同的情况,例如屏幕尺寸大小,分辨率和观众与显示设备的距离。
因此,VMAF规范要求视频分辨率必须与每种模式预期的视频分辨率相匹配(请参阅此处的第一个常见问题解答):
- HD和Phone型号需要1920x1080视频作为输入
- 4K型号需要3840x2160作为输入
在FFmpeg尺度滤波器中,利用双三次插值可以解决源视频与目标视频分辨率不匹配的问题。
例如,要使用HD模型(VMAF_v0.6.1.pkl),我们需要通过使用以下FFmpeg命令来缩放失真的视频(如果不是1920x1080)。
代码语言:javascript复制
代码语言:javascript复制ffmpeg -i <distorted> -i <reference> -lavfi "
[0:v]scale=1920:1080:flags=bicubic[distorted];[distorted]
[1:v]libvmaf=model_path=/usr/local/share/model/VMAF_v0.6.1.pkl" -f null -
代码语言:javascript复制
同样,要使用4K模型,我们需要将失真的视频缩放到3840x2160。
代码语言:javascript复制ffmpeg -i <distorted> -i <reference> -lavfi "
[0:v]scale=3840:2160:flags=bicubic[distorted];[distorted]
[1:v]libvmaf=model_path=/usr/local/share/model/VMAF_4k_v0.6.1.pkl" -f null -
上面的例子考虑到了参考视频已经匹配了VMAF模型所期望的分辨率。
如果不是这样,你也可以应用相同的scalefilter的参考:
代码语言:javascript复制ffmpeg -i <distorted> -i <reference> -lavfi "
[0:v]scale=3840:2160:flags=bicubic[distorted];
[1:v]scale=3840:2160:flags=bicubic[reference];[distorted]
[reference]libvmaf=model_path=/usr/local/share/model/VMAF_4k_v0.6.1.pkl" -f null -
帧同步
VMAF要求参考和失真视频之间的帧同步,因此必须保证帧速率、扫描模式和视频持续时间匹配
下面是实现帧同步的方法。
扫描模式不匹配
传统上将H.264 / AVC实时信号源设置为隔行扫描模式,但是一旦它通过OTT转码器,则输出通常为逐行模式。因此,如果我们想要计算VMAF,我们首先需要规范化扫描模式。
鉴于VMAF模型是使用逐行扫描模式训练的,建议始终对隔行扫描输入进行隔行扫描消除。
扫描模式的规范化可以由FFmpeg通过使用yadif过滤器完成:
代码语言:javascript复制ffmpeg -i <distorted> -i <reference> -lavfi "[1:v]yadif=0:-1:0[ref];[0:v]
[ref]libvmaf=model_path=/usr/local/share/model/VMAF_v0.6.1.pkl" -f null -
上面的命令行假设参考流是隔行扫描的,因此它通过选项mode:parity:deint = 0:-1:0传递给yadif过滤器。这意味着:
- 0:输入中每一帧输出一帧
- -1:启用对字段奇偶校验的自动检测
- 0:对所有帧进行去隔行处理
因此,如果在隔行扫描模式下滤波器输入的帧率为29.97i,那么yadif滤波器在逐行扫描模式下将输出29.97p。
这是交错源最典型的转换方法,但您也可以尝试其他选项。例如,yadif=1:-1:0将为相同的输入生成59.94p的输出。
帧速率不匹配
首先,您需要知道VMAF并不是通过训练来处理帧率转换问题,因此在这里我们将强制输入以人为地使用VMAF。
因此,应谨慎使用scores,而不应将其用作完全可靠的数值。
但是,即使在计算这个有偏分数的情况下也可能是有用的,因为实际上在ABR阶梯上进行帧速率转换是很常见的。
同样,为了强制进行帧速率转换,我们将使用另一个FFmpeg过滤器:
代码语言:javascript复制ffmpeg -i <distorted> -i <reference> -lavfi "[1:v]fps=fps=30[ref];[0:v]
[ref]libvmaf=model_path=/usr/local/share/model/VMAF_v0.6.1.pkl" -f null -
fps过滤器允许您通过添加新帧(通过复制帧)或丢弃它们来设置帧速率,直到达到所需的值。
我们宁愿保留未修改的reference,只对失真的视频应用filter。
起始帧不匹配
有时,参考视频可能会从与失真序列不同的帧开始。
“起始帧”中的这种不匹配将导致两个序列之间的偏移,并导致错误的VMAF scores。
为了正确计算VMAF分数,我们需要同步对齐参考视频和失真视频的前几帧。一种方法是修剪未对齐的视频序列,直到实现帧同步为止。
我们可以使用FFmpeg的修剪过滤器(filter)对视频进行修剪,并确保输出将包含输入的连续子集。
但是首先,我们需要确定在参考视频序列和失真视频序列中都匹配的帧子集的起点和持续时间。这里的挑战是找到我们应该传递给微调滤波器的正确起点。
为了解决这个问题,我们提出了一种基于PSNR的方法,该方法迭代计算失真视频和参考视频之间的PSNR,直到找到匹配项为止。
详细信息
1. 首先,我们提取两个视频样本,由失真视频序列和参考视频序列的前m帧组成,并计算它们之间的峰值信噪比PSNR。这是第一次迭代的后果。我们建议您仅使用少量帧(即m)以降低计算成本。
2. 在第二次迭代中,我们重新计算了PSNR,但将失真的子样本向前滑动了1帧,然后再次计算了PSNR。
3. 这个重复“滑动和计算PSNR”的过程将重复n次,其中n是SyncWindow中适合的视频帧数。SyncWindow是一个持续时间,我们希望在这个持续时间内找到正确的同步值。
4. 如果幸运的话(如果正确选择了SyncWindow),我们将在过程结束时看到最佳PSNR在第i个帧上。这意味着扭曲序列的第i帧与参考的第1帧匹配。
在此过程结束时,我们有足够的信息来应用修剪滤镜。
下图显示了先前描述的迭代。在每次迭代(i)时,都会在reference_subsample和distorted_subsample_i之间计算PSNR。
实际上,每一次迭代的PSNR计算可以如下进行-
代码语言:javascript复制 while <distorted_subsample_i.1st_frame> IN <SYNC_WINDOW>:
getPSNR(reference_subsample, distorted_subsample_i)
<distorted_subsample_i>.next_frame()
可以使用FFmpeg实现getPSNR()函数,如下所示。
代码语言:javascript复制 ffmpeg -i <distorted> -i <reference>
-lavfi "[0:v]trim=start=<OFFSET>:duration=<M>,setpts=PTS-STARTPTS[distorted_subsample];
[1:v]trim=start=0:duration=<M,setpts=PTS-STARTPTS[reference_subsample];
[distorted_subsample][reference_subsample]psnr=stats_file=psnr.log" -f null -
where
代码语言:javascript复制 <OFFSET>: (i-1)*1/fps, and fps is the framerate per second.
<M>: Size in seconds of the subsample sequence. This is a fixed value for all the iterations.
<SYNC_WINDOW>: window time (seconds) in which we want to find the right sync value
举个例子,如果我们为fps = 30的视频序列选择<SYNC_WINDOW> value = 0.3秒,我们会得到如下结果:
代码语言:javascript复制 iteration offset(s) psnr[dB]
1 0.0 21.098356
2 0.03333333333333333 21.132783
3 0.06666666666666667 21.167991
4 0.1 21.204151
5 0.13333333333333333 21.248292
6 0.16666666666666666 21.29118
*7 0.2 33.675342
8 0.23333333333333334 21.363845
9 0.26666666666666666 21.409776
10 0.3 21.451546
代码语言:javascript复制
根据这些值,在第7次迭代时得到最佳的PSNR。
因此,畸变序列的第7帧(距其开始0.2秒)与参考序列的第1帧匹配。
有了这些信息,我们就可以通过调整序列来使用FFmpeg计算VMAF。
代码语言:javascript复制ffmpeg -i <distorted> -i <reference> -lavfi "[0:v]trim=start=<OFFSET>,setpts=PTS-
STARTPTS[distorted];[distorted]
[reference]libvmaf=model_path=/usr/local/share/model/VMAF_v0.6.1.pkl" -f null -
在实践中,有时我们还需要将持续时间参数传递给trim (trim=start=;duration=),以确保畸变序列和参考序列在秒内具有相同的长度。
VMAF使用easyVMAF将它们组合在一起
到目前为止,我们使用一些简单的示例讨论了在计算VMAF之前对视频进行预处理的过程。
但是,在实践中,很常见的是,您需要同时应用先前描述的所有或大部分归一化,即,放大,去隔行,更改帧速率(例如,从29.97到30fps)并同步 时间维度中的扭曲和参考帧。
整个过程无需手动执行,而是在easyVMAF中自动完成,easyVMAF是一个Python脚本,可以完成VMAF所需的规范化过程。
easyVMAF使用FFmpeg和FFprobe进行所有必要的视频编辑和信息收集。它允许我们执行去隔行扫描(Deinterlacing),上/下缩放,帧同步,帧速率适配。
下图显示了easyVMAF的高级概述。
如果您对easyVMAF感兴趣,请访问GitHub repo,在那里您可以查看Docker图像或浏览源代码。
请尝试着在今天的视频中尝试一下!
如果您有任何建议,改进,或您想贡献,请随时提交PRs。
在结束本文之前,下面是运行Docker映像的过程以及命令行参数的说明。谢谢!
代码语言:javascript复制 docker run --rm gfdavila/easyVMAF -h
usage: easyVMAF [-h] -d D -r R [-sw SW] [-ss SS] [-subsample N] [-reverse]
[-model MODEL] [-phone] [-verbose] [-output_fmt OUTPUT_FMT]
Script to easily compute VMAF using FFmpeg. It allows to deinterlace, scale, and sync Ref and Distorted video samples automatically:
Autodeinterlace: If the Reference or Distorted samples are interlaced, deinterlacing is applied
Autoscale: Reference and Distorted samples are scaled automatically to 1920x1080 or 3840x2160 depending on the VMAF model to use
Autosync: The first frames of the distorted video are used as a reference to do sync lookup with the Reference video.
The sync is doing by a frame-by-frame lookup of the best PSNR
See [-reverse] for more options for syncing
As output, a json file with the VMAF score is created
Optional arguments:
-h, --help show this help message and exit
-sw SW Sync Window: window size in seconds of a subsample of the Reference video. The sync lookup will be done between the first frames of the Distorted input and this Subsample of the Reference. (default=0. No sync).
-ss SS Sync Start Time. Time in seconds from the beginning of the Reference video to which the Sync Window will be applied from. (default=0).
-subsample N Specifies the subsampling of frames to speed up calculation. (default=1, None).
-reverse If enabled, it Changes the default Autosync behaviour: The first frames of the Reference video are used as reference to sync with the Distorted one. (Default = Disable).
-model MODEL VMAF Model. Options: HD, HDneg*, 4K. (Default: HD).
-phone It enables VMAF phone models (HD only). (Default=disable).
-verbose Activate verbose loglevel. (Default: info).
-output_fmt OUTPUT_FMT
Output VMAF file format. Options: json or xml (Default: json)
required arguments:
-d D Distorted video
-r R Reference video
* NOTE: HDneg is a VMAF experimental feature not supported yet by FFmpeg.