《H.264/AVC視訊編解碼技術詳解》視訊教程已經在“CSDN學院”上線,視訊中詳述了H.264的背景、标準協定和實作,并通過一個實戰工程的形式對H.264的标準進行解析和實作,歡迎觀看!
“紙上得來終覺淺,絕知此事要躬行”,隻有自己按照标準文檔以代碼的形式操作一遍,才能對視訊壓縮編碼标準的思想和方法有足夠深刻的了解和體會!
連結位址: H.264/AVC視訊編解碼技術詳解
GitHub代碼位址: 點選這裡
一、去塊濾波的基本概念
1.1 去塊濾波的作用
去塊濾波器(Deblocking Filter)是視訊編解碼器中的重要組成部分,其核心作用在于消除編碼過程中産生的圖像塊效應。圖像中的塊效應主要因為以宏塊為基本單元的編碼結構而産生。在編碼中,每個宏塊的子塊都會按照既定分割方式進行預測、變換和量化編碼,在這個過程中可能導緻塊效應的因素主要有以下幾種:
- 由于變換和量化編碼的運算精度誤差導緻邊界出現不連續;
- 由于碼率設定較低,量化強度較大,或者相鄰宏塊的量化參數不一緻導緻重建圖像的細節部分産生差異;
- 由于運動補償時的參考塊位置與目前塊位置關系不一緻導緻重建像素的内容實際上缺乏相關性。
為了解決該問題,在H.264中定義了名為"Deblocking Filter"的像素域的圖像濾波算法,以降低塊與宏塊邊界的像素不一緻性,提升整體視覺主觀體驗。
1.2 去塊濾波器的定義
在H.264的标準文檔中,去塊濾波器定義在8.7節中。在H.264的以下profile中,去塊濾波是必要的組成部分:
- Baseline, Constrained Baseline, Main, Extended, High, High 10, High 4:2:2, High 4:4:4 Predictive;
在以下profile中,去塊濾波器推薦而不強制使用:
- High 10 Intra, High 4:2:2 Intra, High 4:4:4 Intra, CAVLC 4:4:4 iNTRA;
在H.264幀解碼的過程中,去塊濾波器在該幀所有宏塊的解碼像素資料重建完成之後進行。在執行中,該過程按照宏塊位址的順序,對所有的NxN分割模式的宏塊的像素塊分割邊界分别進行,其中不包括整個圖像的邊界以及被标志值disable_deblocking_filter_idc所禁用的邊界。
二、 去塊濾波的執行過程
去塊濾波對于每一個宏塊的亮度和色度分量分别進行。對于宏塊的每一個分量,首先進行垂直方向的濾波,然後進行水準方向的濾波。垂直方向的濾波從左向右進行,水準方向的濾波從上向下進行。在水準和垂直兩方向上,待濾波的塊邊沿分為兩類:半宏塊和1/4宏塊的邊沿。标準文檔中的插圖表示如下:
在上圖中,實線表示半宏塊的邊沿,虛線表示1/4宏塊的邊沿。對于亮度/色度以及不同的參數設定,去塊濾波操作的邊沿不同。對于亮度分量,根據transform_size_8x8_flag的值判斷:
- 如果transform_size_8x8_flag為0,即采用4×4尺寸變換,對實線和虛線的邊沿進行濾波;
- 如果transform_size_8x8_flag為1,即采用8×8尺寸變換,隻對實線的塊邊沿進行濾波;
對于色度分量,隻考慮4:2:0格式,隻對半宏塊邊沿即實線部分進行濾波。
宏塊去塊濾波的過程主要分為如下幾個步驟:
- 确定目前宏塊的鄰域有效性;
- 擷取幾個關鍵的辨別參數:
- fieldMbInFrameFlag:隻考慮幀編碼,該值應為0;
- filterInternalEdgesFlag:如果目前slice中的disable_deblocking_filter_idc的值設為0,則該flag為1;反之為0;
- filterLeftMbEdgeFlag:如果目前slice中的disable_deblocking_filter_idc設為1,或disable_deblocking_filter_idc設為2而且該宏塊不可得,或宏塊為圖像的左側邊沿宏塊,則該flag設為0;反之設為1;
- filterTopMbEdgeFlag:如果目前slice中的disable_deblocking_filter_idc設為1,或disable_deblocking_filter_idc設為2而且該宏塊不可得,或宏塊為圖像的上方邊沿宏塊,則該flag設為0;反之設為1;
- 根據上述關鍵辨別參數執行濾波過程。
2.1 左宏塊邊沿濾波
若辨別位filterLeftMbEdgeFlag設為1,根據協定文檔中8.7.1節的方法執行宏塊亮度分量左側邊沿的濾波。其中chromaEdgeFlag為0,verticalEdgeFlag為1,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (0, k)的k取[0,15]。
2.2 上宏塊邊沿濾波
若辨別位filterTopMbEdgeFlag的值為1,宏塊亮度分量的上水準邊沿進行濾波過程。由于目前設定下MbaffFrameFlag始終為0,是以根據協定文檔中8.7.1節的方法執行濾波。相關參數為chromaEdgeFlag為0,verticalEdgeFlag為1,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (k,0)的k取[0,15]。
2.3 内部塊邊沿濾波
當标志位filterInternalEdgesFlag為1時,執行宏塊内部塊邊沿的濾波。内部塊邊沿的濾波分為水準和垂直兩種。
2.3.1 内部垂直塊邊沿濾波
内部垂直邊沿濾波的步驟為:
- 如果transform_size_8x8_flag為0,根據協定文檔中8.7.1節的方法執行濾波。相關參數為chromaEdgeFlag為0,verticalEdgeFlag為1,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (4,k)的k取[0,15]。該步驟即為第一和第二列塊相鄰邊沿的濾波。
- 根據協定文檔中8.7.1節的方法執行濾波,相關參數為chromaEdgeFlag為0,verticalEdgeFlag為1,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (8,k)的k取[0,15]。該步驟即為第二和第三列塊相鄰邊沿的濾波。
- 如果transform_size_8x8_flag為0,根據協定文檔中8.7.1節的方法執行濾波。相關參數為chromaEdgeFlag為0,verticalEdgeFlag為1,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (12,k)的k取[0,15]。該步驟即為第三和第四列塊相鄰邊沿的濾波。
2.3.2 内部水準塊邊沿濾波
内部水準邊沿濾波的步驟為:
- 如果transform_size_8x8_flag為0,根據協定文檔中8.7.1節的方法執行濾波。相關參數為chromaEdgeFlag為0,verticalEdgeFlag為0,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (k,4)的k取[0,15]。該步驟即為第一和第二行塊相鄰邊沿的濾波。
- 根據協定文檔中8.7.1節的方法執行濾波,相關參數為chromaEdgeFlag為0,verticalEdgeFlag為0,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (k,8)的k取[0,15]。該步驟即為第二和第三行塊相鄰邊沿的濾波。
- 如果transform_size_8x8_flag為0,根據協定文檔中8.7.1節的方法執行濾波。相關參數為chromaEdgeFlag為0,verticalEdgeFlag為1,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (k,12)的k取[0,15]。該步驟即為第三和第四行塊相鄰邊沿的濾波。
2.4 色度分量的濾波
在圖像為彩色圖像的情況下,色度部分同樣需要進行濾波操作。對于色度分量的濾波,其思路類似于亮度分量。
2.4.1 色度左宏塊邊沿濾波
如果filterLeftMbEdgeFlag為1時,根據協定文檔中8.7.1節的方法執行宏塊色度分量左側邊沿的濾波。chromaEdgeFlag為1,verticalEdgeFlag為1,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (0, k)的k取[0,7]。
2.4.2 色度上宏塊邊沿濾波
如果filterTopMbEdgeFlag為1,根據協定文檔中8.7.1節的方法執行宏塊色度分量上方邊沿的濾波。。chromaEdgeFlag為1,verticalEdgeFlag為0,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = ( k,0)的k取[0,7]。
2.4.3 色度分量内部塊邊沿濾波
色度分量的内部塊濾波也分為水準和垂直兩個方向,且隻有在transform_size_8x8_flag為0時執行。
對于水準方向,根據協定文檔中8.7.1節的方法執行濾波,相關參數為chromaEdgeFlag為1,verticalEdgeFlag為0,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (k,4)的k取[0,8]。
對于垂直方向,根據協定文檔中8.7.1節的方法執行濾波,相關參數為chromaEdgeFlag為1,verticalEdgeFlag為1,fieldModeInFrameFilteringFlag等于fieldMbInFrameFlag(幀編碼模式中始終0),(xEk, yEk) = (4,k)的k取[0,8]。
三、塊/宏塊邊沿濾波方法
濾波每一個塊邊沿的方法定義于标準協定文檔的8.7.1節。所需要的步驟包括:
- 确定相關參數:
- chromaEdgeFlag:表明目前資料屬于亮度或色度;
- iCbCr:色度分量索引;
- verticalEdgeFlag:水準、垂直方向标志位;
- fieldModeInFrameFilteringFlag:隔行模式标志位;
- nE:一個邊沿包含的像素數量,亮度為16,色度為8;
- 擷取原重建塊的待濾波像素;
- 根據原像素進行濾波;
- 修改重建像素值。
## 3.1 擷取原重建塊的待濾波像素
對一個塊邊沿上的某一個像素位置進行濾波時,需要擷取該像素位置相鄰的8個原像素值作為參考。标準文檔中的插圖如下:
上圖中的p0和q0代表塊邊界某個位置左右的相鄰像素,根據濾波方向的不同,可能是左右或上下相鄰的像素。以水準塊邊沿濾波為例,采用邊界垂直方向的8個相鄰像素,如下圖所示:
上圖中,紅色像素P0和Q0表示邊界兩側的相鄰像素,其餘藍色像素為濾波所需要的其他相鄰像素。
## 3.2 邊界像素濾波
在擷取到邊界的參考像素後,下一步執行的操作是參考8個像素值進行濾波。濾波過程的具體方法定義在标準的8.7.2節。實作一個邊界的濾波需要三大步驟:
- 計算邊界濾波強度;
- 判斷濾波條件;
- 濾波邊界像素;
3.2.1 計算邊界濾波強度
邊界濾波強度是邊界像素濾波時的一個重要的參數,決定了像素點的濾波采取怎樣的算法。實作方法定義在标準的8.7.2.1節。邊界濾波強度可能的取值有0、1、2、3、4共5個值。其中:
- 0:表示該邊界不需要濾波;
- 1、2:主要用于幀間編碼圖像的濾波;
- 3、4:主要用于幀内編碼圖像的濾波;
本節中主要以幀内編碼為例說明邊界濾波強度的計算方法,即濾波強度取3、4的條件。
- 當濾波邊界為宏塊邊沿,并且邊界相鄰像素p0和q0都屬于幀編碼宏塊,并且任意一個像素的所屬宏塊為幀内編碼或所屬的幀類型為SI或SP時,邊界濾波強度為4;
- 當濾波邊界為子塊邊界,并且邊界相鄰像素p0和q0都屬于幀編碼宏塊,并且任意一個像素的所屬宏塊為幀内編碼或所屬的幀類型為SI或SP時,邊界濾波強度為3;
- 在幀内編碼模式中,同時作為宏塊邊沿和圖像邊沿的像素,濾波強度為0,不進行濾波。
3.2.2 判斷濾波條件
判斷濾波條件的方法定義在8.7.2.2節,所需資料包括邊界兩側的4個像素值p0/p1/q0/q1,顔色空間分量标志位chromaEdgeFlag,邊界濾波強度bS,所屬宏塊的量化參數QPp/QPq,以及在視訊頭部讀取到的兩個文法元素filterOffsetA/filterOffsetB。
首先計算邊界相鄰像素所屬宏塊量化參數QP的平均值:
qPav =(qPp +qPq +1)>>1;
計算查表所需要的兩個索引值:
indexA = Clip3(0, 51, qPav + filterOffsetA);
indexB = Clip3(0, 51, qPav + filterOffsetB);
根據計算得到的indexA和indexB,通過在表8-16中查找對應的alpha和beta值:
根據上述計算得到的資訊,可以獲得濾波判決條件:
filterSamplesFlag=(bS!=0 && Abs(p0 −q0 )<α && Abs(p1 −p0 )<β && Abs(q1 −q0 )<β);
3.2.3 濾波邊界像素
針對邊界濾波強度不同的像素點,采用的方法也相應不同。濾波過程修改的像素值包括邊界兩邊的相鄰像素以及分别向兩個方向擴充兩個的像素值,即根據邊界左右對稱的6個相鄰像素。
對于濾波強度為4的像素點(即非作為圖像邊緣的宏塊邊界),采用如下方法進行濾波:
如果濾波亮度分量,且滿足ap <β && Abs(p0 −q0 )<((α>>2)+2)時,邊界左側或上方的三個濾波後像素的計算方法為:
- p′0 =(p2 +2p1 +2p0 +2*q0 +q1 +4)>>3
- p′1 =(p2 +p1 +p0 +q0 +2)>>2
- p′2 =(2p3 +3p2 +p1 +p0 +q0 +4)>>3
右側或下方的三個濾波後像素的計算方法為:
- q′0 =(p1 +2p0 +2q0 +2*q1 +q2 +4)>>3
- q′1 =(p0 +q0 +q1 +q2 +2)>>2
- q′2 =(2q3 +3q2 +q1 +q0 +p0 +4)>>3
如果濾波色度分量,或者不滿足ap <β && Abs(p0 −q0 )<((α>>2)+2)時,邊界左側或上方的三個濾波後像素的計算方法為:
- p′0 =(2*p1 +p0 +q1 +2)>>2
- p′1 = p1
- p′2 = p2
- q′0 =(2*q1 +q0 +p1 +2)>>2
- q′1 = q1
- q′2 = q2
對于濾波強度為3的像素點(即内部塊邊沿),采用的濾波方法略複雜:
首先依據上面獲得的indexA和邊界濾波強度查表獲得C0值,該值由标準文檔中的表8-17獲得。
擷取參考像素的二級差分值:
ap =Abs(p2 −p0 )
aq =Abs(q2 −q0 )
計算門檻值變量tc:
亮度:tC =tC0 +((ap <β)?1:0)+((aq <β)?1:0)
色度:tC =tC0 +1
計算邊界相鄰像素:
Δ =Clip3(−tC,tC,((((q0 −p0 )<<2)+(p1 −q1 )+4)>>3)) p′0 = Clip1( p0 + Δ )
q′0 = Clip1( q0 − Δ )
對亮度分量,p1/q1的推導方式為:
p′1 =p1 +Clip3(−tC0,tC0,(p2 +((p0 +q0 +1)>>1)−(p1 <<1)) >> 1)
q′1 =q1 +Clip3(−tC0,tC0,(q2 +((p0 +q0 +1)>>1)−(q1 <<1)) >> 1)
其它,p2/q2以及色度分量的p1/q1/p2/q2像素維持原值不變。