h.264 去块滤波

块效应及其产生原因

我们在观看视频的时候,在运动剧烈的场景常能观察到图像出现小方块,小方块在边界处呈现不连续的效果(如下图),这种现象被称为块效应(blocking artifact)。

首先我们需要搞清楚块效应产生的原因。h.264在编码过程中对像素残差进行了DCT变换,变换后得到的DCT系数是与每个像素都相关的,这些系数代表了被变换数据的基础色调与细节。h.264在DCT变换后对DCT系数进行了量化,量化能有效去除相邻像素间的空间冗余,也就是说会抹去元素数据的部分细节。比较理想的情况是量化抹去人眼无法识别的细节部分,但是在低码率的情况下就会导致原始数据的细节丢失过多。而且,DCT变换时基于块的,即将8x8或者4x4的像素残差进行变换后得到8x8或者4x4DCT系数,此时如果进行了低码率的量化,就会使得相邻两个块的相关性变差,从而出现块效应。

h.264的运动补偿加剧了由变换量化导致的块效应。由于运动补偿块的匹配不可能绝对准确,各个块的残差大小程度存在差异,尤其是当相邻两个块所用参考帧不同、运动矢量或参考块的差距过大时,块边界上产生的数据不连续就更加明显。

块效应主要有两种形式:一种是由于DCT高频系数被量化为0,使得强边缘在跨边界处出现锯齿状,称为梯形噪声;另一种经常出现在平坦区域,由于量化导致本来平缓变换的亮度块DC系数发生跳跃,造成变换块的基础色调改变,这种称为格形噪声。

去块滤波在编解码器中的位置

为了减轻和消除视频图像中的块效应,通常会使用滤波器对块边界处的像素进行滤波以平滑像素值的突变,这种滤波被称为去块滤波器(Deblocking Filter)。

标准8.7小节中规定了去块滤波的内容,这部分被称为环路滤波器(loop filter)。环路滤波器是被放置在编解码的图像重建环路当中。在启用了环路滤波的编解码环境中,无论是编码器还是解码器,都是在图像被重建后才进行滤波。在编码器中,滤波后的图像会作为后续编码运动补偿的参考图像;在解码器中,滤波后的图像会被输出显示并且作为后续图像解码重建的参考图像。

滤波前的准备

1. 滤波参数

在标准中,去块滤波会被应用于亮度以及色度宏块的滤波,语法元素disable_deblocking_filter_idc用于控制去块滤波是否打开,它的取值有三个:0~2。

  • 0:开启去块滤波功能,去块滤波能穿越slice边界。
  • 1:关闭去块滤波功能。
  • 2:开启去块滤波功能,但是滤波只能对同一个slice范围内的宏块执行。

2. 滤波边界

去块滤波基于宏块进行,包括亮度宏块以及色度宏块。亮度宏块的宽高为16x16宏块,而色度宏块有几种不同的格式,去块滤波边界如下图:

图中粗线条为滤波边界,其中红色粗线为水平边界(Horizontal edge),蓝色粗线为垂直边界(Vertical edge),滤波边界把宏块分割成多个4x4的块。需要注意的一点是,如果transform_8x8_mode_flag为1,则代表亮度宏块以及4:4:4的色度宏块会采用8x8的DCT,此时亮度宏块以及4:4:4的色度宏块的滤波边界会把宏块分割成8x8的块。

滤波边界还能根据滤波过程是否会用到当前宏块以外宏块来进行细分。宏块的顶部边界、左边界由于处于宏块边缘,滤波的时候肯定需要用到相邻宏块,而其余的滤波边界在滤波时只会用到当前宏块内部的像素。

  • Left MB Edge: 垂直方向上宏块最左边的宏块滤波边界

    • 如果当前宏块为图像的最左边宏块的话,不需要进行左边界滤波
    • 如果规定了只能用当前slice的宏块进行滤波(disable_deblocking_filter_idc=2),并且当前宏块与其左边宏块不为同一slice,那也不需要进行左边界滤波
  • Vertical Internal Mb Edge: 垂直方向上的宏块内部滤波边界。不同宏块类型其中包含的垂直内部滤波边界的数量不同

    宏块格式 Y 4:2:0 Cb/Cr 4:2:2 Cb/Cr 4:4:4 Cb/Cr
    垂直内部滤波边界数目 3 1 1 3
  • Top MB Edge: 水平方向上宏块最顶部的宏块滤波边界
    • 如果当前宏块为图像的最顶部宏块的话,不需要进行顶部边界滤波
    • 如果规定了只能用当前slice的宏块进行滤波(disable_deblocking_filter_idc=2),并且当前宏块与其上方宏块不为同一slice,那也不需要进行顶部边界滤波
  • Vertical Internal Mb Edge: 垂直方向上的宏块内部滤波边界。不同宏块类型其中包含的垂直内部滤波边界的数量不同

    宏块格式 Y 4:2:0 Cb/Cr 4:2:2 Cb/Cr 4:4:4 Cb/Cr
    水平内部滤波边界数目 3 1 3 3

滤波先进行亮度宏块滤波后进行色度宏块滤波,对一个宏块滤波边界的滤波也需要遵循一定顺序

  • 先进行垂直边界滤波,从左到右
  • 后进行水平边界滤波,从上到下

3. 滤波源像素选择

去块滤波所用的源像素分布在边界的两边,分别有4个像素点,如下图所示

p与q像素所在的4x4或者8x8块我们分别成之为P块与Q块。

如果当前编码的图像以帧或者场的方式进行编码,则可以直接按照上述边界两边的位置得到滤波的源像素点。不过如果图像采用帧场自适应方式进行编码(MBAFF),则需要对边界两边的像素进行定位以得到正确的源像素。

我们在前面已经讨论过,块效应是由于对块(block)进行DCT变换量化产生的,去块滤波的目的是消除块效应,因此去块滤波需要正确地定位出进行DCT变换量化的块。在帧场自适应的编码环境下,宏块可以以帧或者场的方式进行编码,但是在宏块进行重建后得到的都是帧宏块,因此我们需要根据实际情况定位出当时进行DCT变换量化的块所在的像素。

以下是在帧场自适应编码环境下,一个垂直边界滤波像素定位的事例

以下是在帧场自适应编码环境下,一个水平边界滤波像素定位的事例

另外,在帧场自适应的编码环境下,如果当前宏块为帧宏块,它的上方宏块为场宏块,那么在进行顶部边界滤波时需要进行两条边界的滤波

滤波过程

1. 估算边界强度

对于滤波边界,我们首先需要根据边界所在的位置已以及宏块的信息来粗略地估计边界两边的像素差距,我们称这个像素差距为边界强度(BS,Boundary Strength)。

判断条件 边界强度 BS

P块或者Q块为帧内编码模式,并且块边缘为宏块边缘
4

P块或者Q块为帧内编码模式
3

P块或者Q块的残差变换系数包含非零系数
2

P块或者Q块的残差变换系数都不包含非零系数,并且P块和Q块的参考帧或运动向量数目(前后向)不同
1

P块或者Q块的残差变换系数都不包含非零系数,并且P块和Q块的参考帧以及运动向量数目(前后向)相同
0

上述表格用于亮度BS的计算,色度宏块的BS沿用其相应亮度宏块的BS。由于表格的描述不尽详细,详情请参考标准8.7.2.1

2. 区分真假边界

在粗略地估算滤波边界强度后,我们需要区分这个边界强度是由于对块进行DCT变换量化引起的块效应(虚假边界)还是视频图像原有的边界(真实边界)。如果是真实边界则不需要进行滤波,如果是虚假边界则需要进行去块滤波。区分真假边界基于下面两个假设:

  • 真实边界两边像素点的差值通常比虚假边界两边像素值要大
  • 对于两边像素值差别很小的真实边界,即使使用了去块滤波,对它的主观效果不会有太大影响

因此,去块滤波应该遵循以下原则:

  • 在平坦区域,即使很小的像素不连续也很容易被人察觉,所以要使用比较强的去块滤波,可以改变较多的像素点
  • 对于复杂的区域,为了保持图像细节,要使用较弱的去块滤波,改变较少的像素点

假设下图为像素点的亮度值分布图,这种情况下两边像素点的差值非常大,根据上面的假设,在p0和q0之间出现的是物体的真实边界,因而不需要进行滤波。

标准h.264中设定了两个阈值α和β来判断真假边界,α表示块与块之间的边界阈值,β表示块内部边界的阈值。对于边界两边的像素点的差值,如果下面三个条件都满足就会被判定为需要滤波的虚假边界,否则就判定为不需要滤波真实边界。

|p0 - q0| < α[IndexA]

|p1 - p0| < β[IndexB]

|q1 - q0| < β[IndexB]

其中α与β可以通过IndexA以及IndexB从表格中得到。IndexA以及IndxeB为表格的索引,他们的计算方法如下

IndexA = Clip3( 0, 51, QPaverage + FilterOffsetA )

IndexB = Clip3( 0, 51, QPaverage + FilterQffsetB )

其中QPaverage = ( QPp+QPq+1) / 2,FilterOffsetA以及FilterOffsetB则为偏移量,偏移量用于调整滤波强度。当需要增加滤波强度时,用正偏移量,可以去除由次优运动估计、编码模式选择不当引起的块效应,改善图像主观质量;当需要减少滤波强度时,用负的偏移量,可以保护图像细节不被滤波器的平滑作用模糊掉。偏移量将在slice头信息中传输,请参考h.264语法结构分析中的deblocking相关语法元素。

Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
α 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 5 6 7 8 9 10 12 13
β 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 3 3 3 3 4 4 4
Index 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
α 15 17 20 22 25 28 32 36 40 45 50 56 63 71 80 90 101 113 127 144 162 182 203 226 255 255
β 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18

由上述式子知道,α与β的取决于QP的大小,IndexA、IndexB与α、β对应值见下表

可见QP越大(Index越大),α与β就越大。QP越大意味着量化误差越大,块效应会越明显,因此阈值也应该取较大值来增大滤波效果,反之阈值应该取较小值。

3. 滤波运算

在前面我们讨论了5种边界强度BS,当边界强度不为0时,就需要进行边界滤波。h.264的边界滤波有两种滤波器

  • BS = 1,2,3,采用强度较弱的滤波器,首先改变p0、q0两个像素点,接着用阈值β判断是否需要调整p1和q1
  • BS = 4,此时有两种强度的滤波器,强滤波器可以改变6个像素点(p0、p1、p2、q0、q1、q2),弱滤波器只改变边界上的两个点(p0、q0)
(1) BS = 1,2,3时的滤波运算

①首先对边界上的两个像素点p0与q0进行滤波,它需要输入p1、p0、q0、q1,滤波过程如下

  1. 先要得到差值Δ,差值的计算方式:Δ = ( (q0-p0)<<2 + (p1-q1) + 4 ) >> 3
  2. 然后需要对差值Δ进行限幅,保证这个差值在一定的范围内,这个范围主要通过查表得到,详情请查看标准8.7.2.3
  3. 用差值Δ来计算新的p0、q0,也就是滤波后的值

②接下来对块内的像素点p1与q1分别进行滤波。4:2:0以及4:2:2色度宏块边界的话是不需要执行这部分的滤波的。如果是要计算p1,则需要输入p2、p1、p0、q0;如果是q1,则需要输入p0、q0、q1、q2。

另外,只有满足|p2-p0|<β才能对p1进行滤波,因为满足这个条件则认为P块内部p1处有虚假边界,p1的滤波过程如下

  1. 先要得到差值Δ,差值的计算方式为:Δ = ( p2 + ((p0+q0+1)>>1) − (p1<<1)) >> 1
  2. 然后需要对差值Δ进行限幅,保证这个差值在一定范围内,这个范围主要通过查表得到,详情请查看标准8.7.2.3
  3. 用差值来计算新的p1

q1的滤波过程也是类似的步骤。

(2) BS = 4时的滤波运算

在h.264的帧内预测编码中,倾向于对纹理简单的区域用16x16亮度预测模式编码(如蓝天、白色墙面等),以达到快速编码的目的。虽然这种方法只会在宏块边界引起轻微的块效应,但是在这种情况下,即使很小的强度值查表也会在视觉上产生陡峭的阶梯状的感觉(色块分层),因而对于这种内容平滑的宏块边界就需要采用较强的滤波器;如果此时宏块边界有大量的细节存在,反而不应做强滤波。对此h.264仍采用阈值法来判断是否存在真实边界,如果不存在大量细节信息,可以做强滤波,反之做弱滤波。

这里的滤波是比较好理解的抽头滤波器,P、Q块上的滤波过程差不多,这里以P块为例。

对于P块的点,如果满足下式,则认为细节信息不多:

$\left\{\begin{matrix}
|p0-q0|&<&(\alpha >> 2)+2\\
|p2-p0|&<&\beta
\end{matrix}\right.$

采用强滤波

$\left\{\begin{matrix}
p0 &= &(p2+2p1+2p0+2q0+q1+4)>>3\\
p1 &= &(p2+p1+p0+q0+2)>>2 \\
p2 &= &(2p3+3p2+p1+p0+q0+4)>>3
\end{matrix}\right.$

否则采用弱滤波,只改变p0点

$p0 = (2p1+p0+q1+2)>>2$

参考文献

ITU-T Rec. H.264 (04-2013) Advanced video coding for generic audiovisual services

陈靖、刘京、曹喜信:深入理解视频编解码技术——基于H.264标准及参考模型

时间: 2024-10-14 22:32:15

h.264 去块滤波的相关文章

h.264并行解码算法2D-Wave实现(基于多核非共享内存系统)

在<Scalable Parallel Programming Applied to H.264/AVC Decoding>书中,作者基于双芯片18核的Cell BE系统实现了2D-Wave并行解码算法. Cell BE架构 首先来了解一下Cell BE.Cell BE全称为Cell Broadband Engine,是一种微处理器架构,Cell处理器由索尼.东芝.IBM共同研发,曾应用于PlayStation 3.Cell BE的架构如下图 一个Cell微处理器中共有9个核心,其中有1个PP

h.264并行解码算法分析

并行算法类型可以分为两类 Function-level Decomposition,按照功能模块进行并行 Data-level Decomposition,按照数据划分进行并行 Function-level Decomposition 在h.264解码时进行功能划分,例如对于四核系统,各个核心分别执行下列任务 熵解码framen 逆量化.逆变换framen-1 预测处理framen-2 去块滤波framen-3 这种并行类型就是流水线类型,但这种类型在h.264解码中会出现以下问题 各个功能部分

[ffmpeg] h.264解码所用的主要缓冲区介绍

在进行h264解码过程中,有两个最重要的结构体,分别为H264Picture.H264SliceContext. H264Picture H264Picture用于维护一帧图像以及与该图像相关的语法元素.其中占用大片内存的结构体成员有以下几个: typedef struct H264Picture { AVFrame *f; int8_t *qscale_table; int16_t (*motion_val[2])[2]; uint32_t *mb_type; int8_t *ref_inde

FMS发布视频流H.264如何设置

FMS这个话题由来已久,H.264这个编码格式也由来已久.FMS不叫FMS了,改叫AMS了.因为是Adobe. 今天就说说flash发布流媒体视频,以H.264编码出现的问题.在网上找,大把的关于as3的H.264视频编码的代码.API就那么几个.可是,当你真正去做,用到流媒体发布和播放的时候,就会发现结果并不是想象的那么美.也许会遇到以下几个问题.1.发布端的视频都不清晰.2.发布端的视频清晰,客户端接受到的视频不清晰.冥冥H.264视频编码备受推崇,高清的帽子早戴上了.为什么会这样呢.这里就

FFmpeg的H.264解码器源代码简单分析:环路滤波(Loop Filter)部分

本文分析FFmpeg的H.264解码器的环路滤波(Loop Filter)部分.FFmpeg的H.264解码器调用decode_slice()函数完成了解码工作.这些解码工作可以大体上分为3个步骤:熵解码,宏块解码以及环路滤波.本文分析这3个步骤中的第3个步骤. 函数调用关系图 环路滤波(Loop Filter)部分的源代码在整个H.264解码器中的位置如下图所示. 单击查看更清晰的图片 环路滤波(Loop Filter)部分的源代码的调用关系如下图所示. 单击查看更清晰的图片 环路滤波主要用于

H.264官方软件JM源代码简单分析-解码器ldecod

前一阵子看了一下H.264官方参考软件JM的源代码,在这里总结一下它的结构.JM编解码H.264的速度相对于FFmpeg来说是非常慢的,但是它的代码写得清晰易懂,更适合做学术方面的研究.JM包含了视频解码器ldecod和视频编码器lencod.本文记录视频解码器ldecod的结构. 函数调用关系图 JM中的H.264视频解码器ldecod的函数调用关系图如下所示.   单击查看更清晰的大图 下面解释一下图中关键标记的含义. 函数背景色函数在图中以方框的形式表现出来.不同的背景色标志了该函数不同的

H.264学习笔记——相关概念

此处记录学习AVC过程中的一些基本概念,不定时更新. frame:帧,相当于一幅图像,包含一个亮度矩阵和两个色度矩阵. field:场,一帧图像,通过隔行扫描得到奇偶两场,分别称为顶场和底场或奇场和偶场. macroblock/MB:宏块,H.264中处理(预测.变换.量化)的基本单元,大小16*16个像素. slice group:条带组,每一帧/场图像中,按照光栅扫面的顺序,将MB/MB对分成多个条带(slice). I/P/B 宏块:I宏块只能利用所在slice中已编码的像素进行帧内预测.

视频通讯 视频技术H.264与AVS的比较

视频编码技术在过去几年最重要的发展之一是由ITU和ISO/IEC的联合视频小组 (JVT)开发了H.264/MPEG-4 AVC[8]标准.在发展过程中,业界为这种新标准取了许多不同的名称.ITU在1997年开始利用重要的新编码工具处理H.26L(长期),结果令人鼓舞,于是ISO决定联手ITU组建JVT并采用一个通用的标准.因此,大家有时会听到有人将这项标准称为JVT,尽管它并非正式名称.ITU在2003年5月批准了新的H.264标准.ISO在2003年10 月以MPEG-4 Part 10.高

FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)

本文分析FFmpeg的H.264解码器的宏块解码(Decode)部分的源代码.FFmpeg的H.264解码器调用decode_slice()函数完成了解码工作.这些解码工作可以大体上分为3个步骤:熵解码,宏块解码以及环路滤波.本文分析这3个步骤中的第2个步骤.由于宏块解码部分的内容比较多,因此将本部分内容拆分成两篇文章:一篇文章记录帧内预测宏块(Intra)的宏块解码,另一篇文章记录帧间预测宏块(Inter)的宏块解码. 函数调用关系图 宏块解码(Decode)部分的源代码在整个H.264解码器