H264 环路滤波器
最近在写h264的解码器,现在写下这篇文章,记录一下,希望能帮助更多人,本文所说的不一定正确,如果发现错误,欢迎更正
什么是环路滤波器
我们在看视频的时候出现很多小方块网格,就像铁丝网一样的东西,每个方块边界出现不连续的现象,这个时候被称为方块效应,最重要的原因是我们编码是基于宏块来编码,变换系数量化过程相对粗糙(量化会损失质量的),反量化的时候恢复的变换系数会有误差,这样就造成了在图像块边缘产生不连续的现象。还有一个原因是帧间的运动补偿预测,因为补偿块可能从不是同一帧的不同位置上的样点复制过来,运动补偿匹配的块不可能绝对准确,这样就会在复制块的边缘上产生不连续的现象。如果参考帧的每个块之间就不连续的话,也会被复制到运动补偿的图像块内,h264采用的4*4变换可以降低这种不连续的现象,但是我们还是需要一个去块滤波器来帮我们降低这种不连续现象,实现块与块之间的平滑过渡。(这里说一句,去块滤波器的复杂度非常高,在我写的解码器里,解码每一帧,滤波器所使用的时间达到了将近40% 难顶)
真假边界
上面我们说了因为我们编码的时候DCT和量化带来了方块效应,我们要想办法把这个不连续性的边界消除就完美了,但是我们忽略了一个问题!我们看下面这副图像,这个图像上面有密密麻麻的网格,边界非常明显,但是这些网格是这张图片本身自带的,不是由量化造成的,如果我们不判断,认为这个是方块效应,就有可能造成新的误差,这个时候我们就要先区分是图像本身的真实边界还是由方块效应造成的假边界,对真实的边界不滤波,对假边界采用不同强度的滤波
边界分析
对宏块内部方块进行编码的时候,宏块边界比内部内部比如4*4块的编码误差大,这个现象我们认为是合理的,对于这个解释为内部点重建是对周围点进行加权平均得到。而边界所用到的加权平均少,所以重建效果差
区分真假边界基于下面两个假设
- 真实边界两边像素点的差值通常比虚假边界两边像素值要大
- 对于两边像素值差别很小的真实边界,即使使用了去块滤波,对它的主观效果不会有太大影响
所以我们应该遵循以下两个规则
- 在平坦区域,即使很小的像素不连续也很容易被人察觉,所以要使用比较强的去块滤波,可以改变较多的像素点
- 对于复杂的区域,为了保持图像细节,要使用较弱的去块滤波,改变较少的像素点
假设下面这张图为亮度样点值分布图,这两边的边界像素点的差值非常大,按照上面的假设,p0和q0是为图片的真实边界,因此不需要滤波。
标准文档定义了两个阈值来判断真假边界,α表示块与块之间的边界阈值,β表示块内部边界的阈值。对于边界两边的像素点的差值,如果下面三个条件都满足就会被判定为需要滤波的虚假边界,否则就判定为不需要滤波真实边界。
⏐p0 − q0⏐ < α (IndexA)
⏐p1 − p0⏐ < β (IndexB)
⏐q1 − q0⏐ < β (IndexB)
α和β值根据边界两边的平均量化参数查表得到
上面我们说量化是造成方块效应的主要凶手,而indexA和indexB由下面式子得到。(FilterOffsetA和FilterOffsetB是偏移量用来调整滤波强度)所以我们知道α和β取决于QP的大小(详情查看标准文档表8-16) QP越大(Index越大),α与β就越大,QP越大意味着误差大,块效应越明显,所以取较大值增强滤波效果
IndexA = Clip3( 0, 51, QPaverage + FilterOffsetA )
IndexB = Clip3( 0, 51, QPaverage + FilterQffsetB )
自适应滤波强度推导
对于滤波边界,我们首先需要根据边界所在的位置已以及宏块的信息来粗略地估计边界两边的像素差距,我们称这个像素差距为边界强度(BS,Boundary Strength)
判断条件 | 强度 |
---|---|
边界两边一个图像块为帧内预测并且边界为宏块边界 | 4 |
边界两边一个图像块为帧内预测 | 3 |
边界两边一个图像块对残差编码 | 2 |
边界两边图像块运动矢量差不小于 1 个亮度图像点距离 | 1 |
边界两边图像块运动补偿的参考帧不同 | 1 |
其它 | 0 |
Bs 值的下降趋势说明最强的方块效应主要来自 于帧内预测模式及对预测残差编码,而在较小程度上与图像的运动补偿有关
滤波强度小于4推导
具体过程详见标准文档8.7.2.3
首先我们要先计算一个阈值变量,以保证这个差值在一定范围内(这个范围主要通过查表得到 表8-17)
通过下述方式得到滤波后得到的样点 p’0 和q’0。
∆ = Clip3(−tC, tC, ( ( ( ( q0 − p0 ) << 2 ) + ( p1 − q1 ) + 4 ) >> 3 ) )
p’0 = Clip1( p0 + ∆ )
q’0 = Clip1( q0 − ∆ )
p1和q1类似差值由下面得到
Δ = ( p2 + ((p0+q0+1)>>1) − (p1<<1)) >> 1
滤波强度等于4推导
在帧内预测,对于简单的场景,比如蓝天这种不复杂的图像采用1616亮度预测,达到快速编码,1616只会在宏块边缘引起轻微的块效应,但是在蓝天这种简单单一的背景下,块效应反而会更明显的呈现出来,给人视觉上更容易发现不连续的现象,所以对这种内容平滑的背景反而要采用更强的滤波,相对在复杂度很高图像上不应该采用强滤波,只有下面跨边界约束条件成立才使用强滤波
⏐p0 − q0⏐ < (α>>2)
滤波过程
这里不涉及场编码的情况,只讨论帧编码
滤波过程是在图像重建过程完成之后才对整个图像执行滤波过程,是对整副图像每个宏块进行滤波
通过disable_deblocking_filter_idc来控制是否滤波以及是否可以穿过不同slice
我们先对每个宏块进行纵向滤波,从宏块最左侧开始
transform_size_8x8_flag==1的时候只滤波实线部分,否则实线虚线都要进行滤波
横向滤波同理先对宏块最上测进行滤波,然后判断transform_size_8x8_flag
- 首先获取p3 p2 p1 p0 | q0 q1 q2 q3八个参考样点
- 然后得到滤波强度(BS)
- 然后得到每个块边缘的阈值变量alpha和beta
- 把重新计算得到的样点替换原来的像素点
代码地址,参考资料
《新一代h264视频编码》
https://blog.csdn.net/lj501886285/article/details/84702809