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宏块,而色度宏块有几种不同的格式,去块滤波边界如下图:

 

image

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

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

image

 

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

 

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

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

 

3. 滤波源像素选择

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

image

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

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

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

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

image

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

image

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

image

 

 

滤波过程

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之间出现的是物体的真实边界,因而不需要进行滤波。

image

标准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相关语法元素。

Index012345678910111213141516171819202122232425
α00000000000000004456789101213
β00000000000000002223333444
Index2627282930313233343536373839404142434445464748495051
α15172022252832364045505663718090101113127144162182203226255255
β66778899101011111212131314141515161617171818

由上述式子知道,α与β的取决于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,滤波过程如下

image

  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的滤波过程如下

image

  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标准及参考模型

转载于:https://www.cnblogs.com/TaigaCon/p/5500110.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DataNucleus 3.0与Hibernate 3.5

如官方产品站点所述&#xff0c; DataNucleus Access Platform是现有的最符合标准的开源Java持久性产品。 它完全符合JDO1 &#xff0c; JDO2 &#xff0c; JDO2.1 &#xff0c; JDO2.2 &#xff0c; JDO3 &#xff0c; JPA1和JPA2 Java标准。 它还符合OGC简单功能规范&#xf…

AngularJS 的常用特性(二)

3、列表、表格以及其他迭代型元素 ng-repeat可能是最有用的 Angular 指令了&#xff0c;它可以根据集合中的项目一次创建一组元素的多份拷贝。 比如一个学生名册系统需要从服务器上获取学生信息&#xff0c;目前先把模型之间定义在 JavaScript 代码里面&#xff1a; 1 var stud…

Ruby,Python和Java中的Web服务

今天&#xff0c;我不得不准备一些示例来说明Web服务是可互操作的。 因此&#xff0c;我已经使用Metro使用Java创建了一个简单的Web服务&#xff0c;并在Tomcat上启动了它。 然后尝试使用Python和Ruby消耗它们。 这是全部完成的过程… Java中的Web服务 我从Java中的简单Web服…

用动画切换按钮的状态

用动画切换按钮的状态 效果 源码 https://github.com/YouXianMing/UI-Component-Collection // // BaseControl.h // BaseButton // // Created by YouXianMing on 15/8/27. // Copyright (c) 2015年 YouXianMing. All rights reserved. //#import <UIKit/UIKit.h> c…

Java泛型快速教程

泛型是Java SE 5.0引入的一种Java功能&#xff0c;在其发布几年后&#xff0c;我发誓那里的每个Java程序员不仅听说过它&#xff0c;而且已经使用过它。 关于Java泛型&#xff0c;有很多免费和商业资源&#xff0c;而我使用的最佳资源是&#xff1a; Java教程 Java泛型和集合…

876. 链表的中间结点

给定一个头结点为 head 的非空单链表&#xff0c;返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点 代码一&#xff1a; 自己想的一个方法 class Solution {public ListNode middleNode(ListNode head) {ListNode p1 head;ListNode p2 head;//i,j…

Spark系列—02 Spark程序牛刀小试

一、执行第一个Spark程序 1、执行程序 我们执行一下Spark自带的一个例子&#xff0c;利用蒙特卡罗算法求PI&#xff1a; 启动Spark集群后&#xff0c;可以在集群的任何一台机器上执行一下命令&#xff1a; /home/spark/spark-1.6.1-bin-hadoop2.6/bin/spark-submit \ --class o…

JVM选项:-client vs -server

您是否曾经在运行Java应用程序时想知道-client或-server开关是什么&#xff1f; 例如&#xff1a; javaw.exe -client com.blogspot.sdoulger.LoopTest也显示在java.exe的“帮助”中&#xff0c;例如&#xff0c;其中的选项包括&#xff1a; -client选择“客户端” VM -serv…

3.1存储管理操作系统

存储器管理的对象是主存&#xff08;内存&#xff09;。其主要功能包含分配和回收主存空间、提高主存的利用率、扩充主存、对主存信息实现有效保护。存储器的结构为&#xff1a;寄存去、缓存、主存、外存。逻辑地址&#xff08;对用户角度。程序存放的位置&#xff09;、物理地…

了解和扩展Java ClassLoader

Java ClassLoader是项目开发中Java的关键但很少使用的组件之一。 就我个人而言&#xff0c;我从未在任何项目中扩展ClassLoader&#xff0c;但是拥有自己的可以自定义Java类加载的ClassLoader的想法让我感到很兴奋。 本文将概述Java类加载&#xff0c;然后继续创建自定义ClassL…

CAD教程-AL对其命令

AL可以实现不规则的对其功能 1.第一步按下AL&#xff0c;按下Enter 2.选择第一个源点 3.选择第一个目标点 4.选择第二个源点 5.选择第二个目标点 6.按下Enter&#xff0c;完成移位 转载于:https://www.cnblogs.com/weloveshare/p/4739873.html

(一二四)tableView的多组数据展示和手动排序

最近在写一个轻量级的网络游戏&#xff0c;遇到了技能优先顺序手动排序的需求&#xff0c;我就想到了iOS自带的tableView编辑功能&#xff0c;对其进行了初步探索&#xff0c;最后做出的效果如下图所示&#xff1a; 点击左边可以删除&#xff0c;拖住右边可以手动排序&#xff…

知道这 20 个正则表达式,能让你少写 1,000 行代码

CocoaChina05-13正则表达式&#xff0c;一个十分古老而又强大的文本处理工具&#xff0c;仅仅用一段非常简短的表达式语句&#xff0c;便能够快速实现一个非常复杂的业务逻辑。熟练地掌握正则表达式的话&#xff0c;能够使你的开发效率得到极大的提升。下面是技匠整理的&#x…

元素分类--块级元素(特点:独占一行, 宽高边距可改)

什么是块级元素&#xff1f;在html中<div>、 <p>、<h1>、<form>、<ul> 和 <li>就是块级元素。设置display:block就是将元素显示为块级元素。如下代码就是将内联元素a转换为块状元素&#xff0c;从而使a元素具有块状元素特点。 a{display:b…

站立会议05(第二次冲刺)

一、站立会议信息&#xff08;配站立会议照片&#xff09; 第五天我们继续开发&#xff0c;把注册验证信息完善一下&#xff0c;将开始网站公共主页的开发。 二、任务进度 第五天我们注册验证完成。 三、任务看板&#xff08;图&#xff09; 四、燃尽图&#xff08;图&#xff…

[SoapUI] DataSource, DataSourceLoop, DataSink

Script assertion in login: 转载于:https://www.cnblogs.com/MasterMonkInTemple/p/4748189.html

将CAPTCHA添加到您的GWT应用程序

什么是验证码&#xff1f; 在一个充满恶意机器人的世界中&#xff0c;您该怎么做才能保护您宝贵的Web应用程序&#xff1f; 您真正应该做的基本事情之一就是向其中添加CAPTCHA功能。 如果您不熟悉&#xff08;听起来有些奇怪&#xff09;&#xff0c;则CAPTCHA是确保用户实际上…

SQL基础语句

数据库面试常见题 一、SQL语言包括数据定义语言、数据操作语言、数据控制语言和事务控制语言1&#xff1a;DDL(Data Definition Language)&#xff0c;是用于描述数据库中要存储的现实世界实体的语言。 CREATE TABLE - 创建新表 ALTER TABLE - 变更&#xff08;改变&#xff0…

iOS学习——ScrollView图片轮播和同类控件优先级问题

iOS学习——ScrollView的使用和同类控件优先级问题 1. 布置界面 ScrollView的使用非常简单&#xff0c;只有三步 1.1 添加一个scrollview 1.2 向scrollview添加内容 1.3 告诉scrollview中内容的实际大小 首先做第一步&#xff0c;布置界面。 拖拽一个scrollview就可以了 就…

Git 分支管理和冲突解决

创建分支 git branch 没有参数&#xff0c;显示本地版本库中所有的本地分支名称。 当前检出分支的前面会有星号。 git branch newname 在当前检出分支上新建分支&#xff0c;名叫newname。 git checkout newname 检出分支&#xff0c;即切换到名叫newname的分支。 git checkout…