
导语git
视频已经成为咱们现代生活中不可或缺的元素,众所周知,视频的原始数据量大的惊人,不利于存储和传输!因而乎有了视频编码,不一样的编码器,不一样的参数,软件与硬件,到底哪种编码编的好呢?因而乎就有了视频编码质量评价!一块儿来看看!
github
本文框架web

正文算法
视频编码质量评价,主要分为主观评价和客观评价!主观评价主要是肉眼所见对编码后的视频质量给出评价!客观评价主要利用一些统计学的概念来评价视频编码的质量。编程
主观评价微信
主观评价,顾名思义,就是人眼主观上对编码后的视频的感觉,进而给出的评价!带有必定的主观性,只有在画面质量明显不一样时才能给出比较合理的评价!以下图,左边的图明显会比右边的画面质量要差一些(舒适提示,双击图片,点击查看效果哦):框架




大部分时候,画面质量在人眼看来差异并非很大,以下面的两张图,这样也就没法合理的评判画面质量!机器学习




因而乎,颇有必要的客观评价就出现了。ide
客观评价svg
客观评价主要是基于一些统计学的特性,衡量不一样编码器编码以后产生的图像,哪一些质量更好!主要有PSNR,SSIM,BD-Bitrate/BD-Psnr以及Vmaf。

PSNR

PSNR,英文全称peak signal to noise ratio,中文译做峰值信噪比!一般图像通过压缩以后,在某种程度上会与原始图像不一样。为了衡量通过编码后的图像的品质,一般会参考psnr来衡量编码质量是否可以使人满意!

PSNR的计算公式以下:

咱们看到公式中,包含MSE和n,n表示编码时采用的bit深度,如8bit的状况下n为8,10bit的状况下n为10;MSE表示编码后图像与原始图像的均方差(方差的平均数),MSE的定义以下:

从统计学来说,方差表示波动性,方差越小,表示波动越小,越稳定,psnr的计算公式中,将方差做为分母,而后再取对数,所以psnr的值越高越好。
psnr计算结果的单位为dB,其值越高,表示画面质量越好!
通常,psnr值高于40dB,表示画面质量极好,(很是接近于原始图像);
psnr值在30dB-40dB之间,表示画面质量较好(有失真但可接受);
psnr值在20dB-30dB之间,表示画面质量差;
psnr值小于20db表示画面不可接受!
咱们经过编程模拟一下这个过程(这里使用c语言模拟)
#include <math.h>
uint8_t src[3][3] = {
7, 6, 4,
4, 3, 5,
5, 8, 6
};
uint8_t dst[3][3] = {
7, 7, 5,
4, 2, 5,
4, 8, 5
};
double cal_mse(int src[m][n], int dst[m][n])
{
double mse = 0.0;
int i = 0, j = 0;
for (i = 0; i < m; i++)
{
for(j = 0; j < n; j++)
{
int tmp = dst[i][j] - src[i][j];
mse += (tmp * tmp);
}
}
return mse/m/n;
}
double cal_psnr(double mse, uint8_t bit_depth)
{
double psnr = 0.0;
psnr = 10 * log(10, (pow(2, bit_depth) - 1) * (pow(2, bit_depth)) / mse);
return psnr;
}
实际上,强大的FFmpeg也能够完成这个任务!
ffmpeg -s 1920x1080 -i src.yuv -s 1920x1080 -i dst.yuv -lavfi psnr="stats_file=psnr.log" -f null –
mse_avg:1.00
mse_y:1.26 mse_u:0.49 mse_v:0.47
psnr_avg:48.12
psnr_y:47.12 psnr_u:51.19 psnr_v:51.37
看起来编码的效果还不错!

SSIM

PSNR指标比较经常使用,可是不能体现编码先后图像之间的相关性,而SSIM能够从亮度,对比度和结构三个方面来描述编码先后图像之间的相关性。

亮度相关性
对离散信号,咱们用均值做为亮度预测的估计值。均值的计算方式以下:
float cal_average(uint8_t src[m][n])
{
int i = 0, j = 0;
int sum = 0;
for(i = 0; i < m; ++i)
{
for(j = 0; j < n; ++j)
{
sum += src[i][j];
}
}
return sum / m / n;
}
基于两个图像的均值,定义一个亮度对比函数以下:

计算图像的标准差,计算方式以下:
float cal_varianece(uint8_t src[m][n])
{
int i = 0, j = 0;
double var = 0.0;
float avg = cal_average(src);
for(i = 0; i < m; i++)
{
for(j = 0; j < n; j++)
{
var += pow((src[i][j] - avg), 2);
}
}
return var / m / n;
}
float cal_standard_deviation(uint8_t src[m][n])
{
return sqrt(cal_varianece(src));
}
标准差能够用做对比度估量值。基于标准差定义一个对比度对比函数以下:

结构相关性
利用两幅图像之间的协方差,能够定义一个结构对比函数以下:

其中:


对于亮度,对比度,结构都有了对比函数以后,能够最终定义SSIM的实现,SSIM定义以下:

如此定义的SSIM,表示了图像的亮度,对比度以及结构的相关性,若是为1表示彻底一致;
对于原始图像和编码后重建的图像按照SSIM来评价:
若是SSIM的置越接近于1,表示编码后的图像与原始图像相关性更强,能够理解为编码的失真更小;
若是SSIM的值越接近于0,编码编码后的图像与原始图像相关性更弱,能够理解为编码的失真更大。
咱们用代码来模拟一下这个计算过程以下:
首先是计算协方差:
float cal_cov(uint8_t src[m][n], uint8_t dst[m][n])
{
float sum = 0.0;
float avg_src = cal_average(src);
float avg_dst = cal_average(dst);
for(int i = 0; i < m; i++)
{
for(int j = 0; j < n; j++)
{
sum += (src[m][n] - avg_src)(dst[m][n] - avg_dst);
}
}
return sum / (m * n - 1);
}
有了协方差以后,咱们就能够来总体的计算SSIM的值了,以下:
float cal_ssim(uint8_t src[m][n], uint8_t dst[m][n])
{
uin8_t depth = 8;
float L = pow(2, depth) - 1;
float C1 = pow(0.01 * L, 2);
float C2 = pow(0.03 * L, 2);
float C3 = C2 >> 1;
float avg_src = cal_average(src);
float avg_dst = cal_average(dst);
float var_src = cal_varianece(src);
float var_dst = cal_varianece(dst);
float deviation_src = cal_standard_deviation(src);
float deviation_dst = cal_standard_deviation(dst);
float cov_xy = cal_cov(src, dst);
// 亮度对比函数
float l_xy = (2 * avg_src * avg_dst + C1) / (pow(avg_src, 2) + pow(avg_dst, 2) + C1);
// 对比度对比函数
float c_xy = ( 2 * deviation_src * deviation_dst + C2) / (pow(deviation_src, 2) + pow(deviation_dst, 2) + C2);
// 结构对比函数
float s_xy = (cov_xy + C3) / (deviation_src * deviation_dst + C3);
return l_xy * c_xy * s_xy;
}
一样,借助FFmpeg咱们也能够实现ssim的计算,命令以下:
ffmpeg -s 1920x1080 -i src.yuv -s 1920x1080 -i dst.yuv -lavfi ssim="stats_file=ssim.log" -f null -
Y:0.987967 U:0.993548 V:0.993861
All:0.989880

BD-Bitrate/BD-Psnr

psnr和ssim分别描述了编码的信号噪声比和编码后图像与原始图像之间的类似度,但这依然还不够,咱们来看一种状况。
编码的过程常常要在质量和码率之间取得一个很好的平衡,质量越高感官越好,可是码率随着也会水涨船高,带宽对当前的视频行业而言依然是一个巨大的成本。
评价编码质量,假设psnr上升了,同时码率也降低了,这个时候是咱们梦寐以求的场景;但是若是psnr上升了,而码率也随着上升了,这个时候就须要权衡更注重质量,仍是更但愿节约带宽而牺牲带宽。随之而来的问题也就来了,怎么去评价这个选择过程呢,就出现了BD-Bitrate和BD-Psnr。
BD-Bitrate就是在假定码率的状况下,来查看psnr的值,也就是在特定码率下寻找更高质量的编码;
BD-Psnr就是在假定编码质量的状况下,来查看比特率的值,也就是在特定编码质量下寻找更合适的码率。
BD-Bitrate和Bd-Psnr的计算通常经过采样多个值(通常用3次多项式拟合,因此最少须要四个点),而后进行曲线拟合,绘制拟合曲线,获得相应的图表,进而进行选择判断。
H.264 High Profile |
H.264 Baseline Profile |
||
Bitrate |
PSNR |
Bitrate |
PSNR |
686.76 |
40.28 |
893.34 |
40.39 |
309.58 |
37.18 |
407.8 |
37.21 |
157.11 |
34.24 |
204.93 |
34.17 |
85.95 |
31.42 |
112.75 |
31.24 |
咱们以Psnr为横坐标,bitrate为横坐标,获得拟合曲线以下图:
从拟合后的曲线咱们能够看到,当bitrate小于400的时候,在给定的比特率的前提下,编码选择H.264的High Profile会得到更高的编码质量,若是bitrate大于400时,给定bitrate的状况下,编码选择H.264的Baseline Profile会得到更高的编码质量,这就是Bd-Bitrate的意义。
对于Bd-psnr,从图中咱们能够看到,给定psnr的状况下,编码选择H.264的Baseline Profile,码率永远比编码选择H.264的High Profile要高,这既是Bd-psnr的意义。

Vmaf

Psnr/Ssim这些指标一般在编码器内部,用于对编码决策进行优化并估算最终编码后视频的质量,可是因为这些算法衡量标准单一,缺少对画面先后序列的整体评估(可是先后帧之间的相关性与编码的质量息息相关),致使计算的结果不少状况下与主管感觉不相符。

Vmaf就是解决这个问题的,vmaf全称Video Multimethod Assessment Fusion,是大名鼎鼎的奈飞公司(Netflix)提出来的一种编码质量评价的方法。
面对不一样特征的视频源、编码失真以及失真程度,每一个衡量指标各有优劣,奈飞经过使用机器学习算法,为每个基本的指标分配必定的权重,“融合”为一个最终指标,这样就能够保留每个基本指标的评价优点,最终获得更精确的分数,这就是vmaf的核心理念。
vmaf选择的基本指标主要有视觉信息保真度,简写为VIF,细节丢失指标,简写为DLM和运动量指标。
该项目提供的命令行可执行程序为vmafossexec,准备原始的yuv文件和对应的编码后重建的yuv文件,而后使用以下命令,便可计算vmaf:
vmafossexec yuv420p 576 324 src01_hrc00_576x324.yuv src01_hrc01_576x324.yuv vmaf_v0.6.1.pkl --log vmaf_output.xml --psnr --ssim --subsample 5
命令中576,324表示视频分辨率,--psnr和--ssim表示输出psnr和ssim的值,--subsample表示将多少个图片做为一组,vmaf_v0.6.1.pkl机器学习算法所使用的的模型。

交流群已开启,有须要的朋友,公众号后台回复“交流群”,获取入群方式!



扫码关注了解更多
本文分享自微信公众号 - 视界音你而不一样(WorldOfVideoAndAudio)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。