前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >视频编码质量评价

视频编码质量评价

作者头像
视界音你而不同
发布2021-01-06 14:21:41
1.8K1
发布2021-01-06 14:21:41
举报

导语

视频已经成为我们现代生活中不可或缺的元素,众所周知,视频的原始数据量大的惊人,不利于存储和传输!于是乎有了视频编码,不同的编码器,不同的参数,软件与硬件,到底哪一种编码编的好呢?于是乎就有了视频编码质量评价!一起来看看!

本文框架

正文

视频编码质量评价,主要分为主观评价和客观评价!主观评价主要是肉眼所见对编码后的视频质量给出评价!客观评价主要利用一些统计学的概念来评价视频编码的质量。

主观评价

主观评价,顾名思义,就是人眼主观上对编码后的视频的感受,进而给出的评价!带有一定的主观性,只有在画面质量明显不同时才能给出比较合理的评价!如下图,左边的图明显会比右边的画面质量要差一些(温馨提示,双击图片,点击查看效果哦):

大部分时候,画面质量在人眼看来差别并不是很大,如下面的两张图,这样也就无法合理的评判画面质量!

于是乎,很有必要的客观评价就出现了。

客观评价

客观评价主要是基于一些统计学的特性,衡量不同编码器编码之后产生的图像,哪一些质量更好!主要有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语言模拟)

代码语言:javascript
复制
#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也可以完成这个任务!

代码语言:javascript
复制
ffmpeg -s 1920x1080 -i src.yuv -s 1920x1080 -i dst.yuv -lavfi psnr="stats_file=psnr.log" -f null –

笔者测试的编码过程计算后的结果如下:

代码语言:javascript
复制
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

看起来编码的效果还不错!

注:dst.yuv文件为src.yuv编码后的重建帧(编码之后再解码)

SSIM

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

亮度相关性

对离散信号,我们用均值作为亮度预测的估计值。均值的计算方式如下:

代码语言:javascript
复制
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;
}

基于两个图像的均值,定义一个亮度对比函数如下:

对比度相关性

计算图像的标准差,计算方式如下:

代码语言:javascript
复制
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,编码编码后的图像与原始图像相关性更弱,可以理解为编码的失真更大。

我们用代码来模拟一下这个计算过程如下:

首先是计算协方差:

代码语言:javascript
复制
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的值了,如下:

代码语言:javascript
复制
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的计算,命令如下:

代码语言:javascript
复制
ffmpeg -s 1920x1080 -i src.yuv -s 1920x1080 -i dst.yuv -lavfi ssim="stats_file=ssim.log" -f null -

笔者测试的文件ssim的结果如下:

代码语言:javascript
复制
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

我们以Bitrate为横坐标,psnr为纵坐标,得到拟合曲线如下图:

我们以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和运动量指标。

具体怎么来计算vmaf呢,官方给出具体的例子,且在github上开源(点击阅读原文链接可跳转到该项目):

当前该项目获得2.1k的star和464的fork,不错的成绩。该项目提供了多种计算vmaf的方式,使用命令行的方式,使用C语言库,使用Python的方式,使用Docker的方式,以及结合FFmpeg一起使用的方式,这里演示一下命令行的方式,其他方式,感兴趣的读者可以详细研究。

该项目提供的命令行可执行程序为vmafossexec,准备原始的yuv文件和对应的编码后重建的yuv文件,然后使用如下命令,即可计算vmaf:

代码语言:javascript
复制
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机器学习算法所使用的的模型。

利用上述命令得到的结果如下:

红色框选的部分是计算出来的psnr,ssim以及vmaf的值,vmaf的值越大,表明编码的质量越好,前后帧之间的相关性越强,失真越小。

注:由于vmaf计算的github项目开源,代码及相关资源可能发生变更,请以实际最新的为准。

关于编码质量的评价,终于写完了,花费数日,原创着实不易,不谦虚的说,关于编码质量的评价,全网貌似找不到更全的了,希望对大家有用,点个赞,点个在看,就是对作者最大的鼓励,也非常期待你的关注和入群,这里是“视界音你而不同”,一个专讲音视频视界里开发事的公众号!等你!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 视界音你而不同 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图像处理
图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档