paper: Sample Adaptive Offset for HEVC
《HEVC標准介紹、HEVC幀間預測論文筆記》系列博客,目錄見:http://www.cnblogs.com/DwyaneTalk/p/5711333.html

一、概述:這是目前H265中比較熱門的技術,根據以前的測試,SAO性價比遠遠超過Deblock和ALF.
1、 SAO標准框架中位置:
編碼器端:
從流程中可以看到,SAO和ALF是loop內的操作,接在Deblockingfilter(也是loop內操作)的后面,輸入包括原始的YUV圖像和Deblocking的輸出,最后產生部分需要參數需要entropy進行編碼。ALF是類似的。
解碼器端:
2、SAO起源:
SAO原始的思想來自於Samsung的提案JCTVC-A124,可以參考這個文檔獲得詳細的信息。在三星的提案中提出了比較復雜的BDC(Band- correction, 位於ALF和RPB之間)和EXC(extreme-valuecorrection,位於DeblockingFilter(DF)和ALF之間,也就是現在SAO的位置),BDC和EXC都是對pixel進行分類,然后為每一個分類分配一個offset值。這個offset就是在entropy中要編碼的參數。不同的是,BDC使用的是pixel的intensity(Luma值)來對pixel進行分類;而EXC使用的模板中心pixel和neibor pixel之間的梯度來進行的分類(edge特性).
使用經過BDC/EXC處理后的參考幀,能夠取得更好的壓縮率,但是因為BDC/EXC太復雜,因此沒有被H265采用。但是基於BDC/EXC提出的SAO(JCTVC-BO77/C147/D122/E049)最后被采用了。在原始的提案中SAO分為LUMA SAO和CHROMA SAO(JCTVC-F056)。SAO的offset包含BO(Band offset)和EO(Edgeoffset)。SAO采用了不同於BDC/EXC的pixel分類的方法,降低了復雜度。
3、SAO理論基礎
在對SAO算法分析之前,需要對三星的BDC/EXC的算法進行了解,參考JCTVC-A124文檔。
第一次提出了幾個概念:
CU : CodingUnit,可以是16x16,32x32,64x64,128x128(后被舍棄)。然而,CU的size可以不是固定的,而是可以變化的,在SPS中定義了LCU/SCU來限制CUsize的變化范圍。(必須是正方形)
sps->log2_min_coding_block_size_minus3 (SCU)
sps->log2_diff_max_min_coding_block_size(LCU)
可以把一個picture划分成LCU的集合,在每一個LCU中再進行CU的划分(CUhierarchy Depth). Hierarchy 的層次決定了可以出現的CU的size的數目: 比如
LCU =64x64, MAX_hierarchy_depth = 4
那么CU可以出現的size只有5種,為:
64線4(LCU), 32x32 , 16x16, 8x8(SCU)
在一個LCU中可以包含INTER CU和INTRA CU,因此CU才是等同於MB。LCU只是一個概念上的值,在編碼上還是以CU為單位。
PU: PredictionUnit,是prediction時使用的size,包括intra prediction/interprediciton類似於H264中的partition。
TU: transform Unit, DCTtransform時使用的unit,比如DCT4X4/8X8/16X16/32X32/64X64,可以包含一個或者多個PU。更大的DCTsize有利用處理超分辨率的圖像。
在H265中提供了更大的size的選擇。這也是為了支持超分辨率的圖像的原因。
二、 H265 draft SAO 算法原理
通過PSNR的計算公式可以看到,重構數據和原始YUV之間的差的平方和是決定PSNR的因素。SAO通過分析deblocking后的數據和原始YUV之間的關系來對deblock后的數據進行delta操作,使得盡量接近原始YUV,達到提高PSNR的目的。
一個最基本的想法就是把deblock的重構數據和原始YUV中每一個相同位置的pixel做差值,把這個差值傳給decoder,這樣可以完全恢復原始YUV.但是這實際上是不現實的,如果每一個pixel都傳輸一個offset,這會導致碼率會非常的高,達不到壓縮的效果(如同DPCM)。H265在碼率和PSNR之間做了一個tradeoff,以較小的碼率增加來提高PSNR。下面就看H265是怎么做的。
H265是基於CTB來做SAO。通過分析deblock重構pixel和原始輸入YUV之間的關系將pixel分成了三種SAO模式:
如上表中可以看到,可以不做SAO/Band offset/edge offset 三個mode。
1、EdgeOffset mode:
在這種模式下,SAO首先需要為該CTB選擇使用哪一種梯度模式,水平/垂直/45度/135度,這是用sao_eo_class來表示,選擇過程通過RDO。
當為某個CTB選擇使用了上面某種梯度模式后,開始計算該CTB中的當前sampleP和相鄰2個pixel之間的關系,用edgeIdx表示:
因為edgeIdx的計算是針對deblocking以后的重構圖像進行的,encoder和decoder使用相同的方法來計算,因此不需要傳輸這個信息給decoder,而是可以由decoder自己來計算,這樣雖然增加了計算量,但是可以降低碼率。
對於edgeIdx 為0的flatarea,可以不需要做任何操作。對於1~4,SAO為每一個edgeIdx分配了一個offset,這個offset會add到重構像素中。因為SAO不是為每一個pixel分配一個offset,而是先把pixel進行梯度的計算,並且做edgeIdx的分類,對每一個edgeIdx類分配一個offset(對每一個CTB有4個offset就足夠),這樣可以減少碼率的消耗。另外,為了進一步降低碼率,H265SAO規定對於edgeIdx=1,2這兩種情況下,offset值必須是正數;對於edgeIdx=3,4時,offset必須是負數。通過這種強行的要求,符號位可以不進行編碼。
2、Bandoff Mode:
SAO encoder把有效的YUV取值范圍(0-255 fullRange,16-235 BT601/709)平均分為32個band(如下圖,如果是0-255,就是每一個band的范圍是8,一共分成32個band),通過某些算法來選擇其中連續的4個band進行補償,當CTB中的sample的Luma/Chroma處於這4個選定的band中時,需要對這個sample進行補償(把該band相關的offset值加到sample的值上)。
encoder端如何選擇4個band:
從上面這個圖中可以看到這個原理:在encoder端會統計原始圖像當前CTB中的sample的Luma/chroma值,做32band的直方圖統計,每一個band中包含的該YUV中的sample求均值,下面舉個例子:
比如假設有一個band是31-38,假設該CTB中有3個pixel的值在這個band中,分別為:32、34、36。這樣可以知道原始YUV該CTB中的sample出現在這個band中的均值為(32+34+36)/3= 34。對deblock后的重構圖像同樣做這樣的處理,也求出該band中的均值,假設為32.
那么可見,deblocking后的重構YUV和原始YUV在該CTB上,並且該band上有均值上的差值為34-32=+2.SAO因此可以分配band offset=+2到這個band上,在decoder端,為每一個處於該band上的deblocking后的sample值加上2,這樣可以保證在該band上出現的重構pixel和原始YUV上的該CTB的該band上的均值是相等的。
對32個band都做這樣的處理,最后選擇連續4個,offset值最大的band作為最終確定的需要補償的band。並且起始band值和4個bandoffset值寫到碼流中傳輸給decoder。 通過這種bandoffset的方式,可以把均值差別最大的4個band補償成均值相等,來拉近原始YUV和重構圖像之間的差值。
一個問題:為什么band offset模式中只是選擇4個連續的band?標准給出的答案是:
1. 在flatarea部分,大部分的pixel的取值應該會集中在很少的幾個band中,因此使用連續的4個band能夠覆蓋大部分的pixel。(也就是說如果對flatarea的某一個CTB做直方圖的話,這個pixel會很集中在很少的幾個取值點,因此使用4個連續band可以很好的覆蓋.
2. 因為edgeoffset模式使用了4個offset值,為了不增加碼率,bandoffset也復用了這4個offset值的syntax,這樣不需要另外再增加syntax來專門表示bandoffset。
附錄上H265語法來表示上面的信息:
從上面的語法中可以看到:
對於edgeoffset模式,提供sao_eo_class_luma/chroma的值來選擇使用什么模式的梯度。並且為1-5這4種edgeIdx提供了offset值,一共4個offset。沒有符號位提供。
對於band offset模式,提供了sao_band_position來表示4個連續band的起始band是哪一個。並且為這4個band分別提供了bandoffset值,並且提供了符號位。
另外,如果當前CTB的SAO參數和左邊或者上面的CTB的SAO參數相同,那么也就不需要為當前CTB再傳輸SAO參數了,而是直接使用左邊CTB或者TOPCTB中的SAO參數即可。這樣可以進一步降低碼率。這就是sao_merge_left_flag/sao_merge_up_flag的作用。需要注意的是因為H265引入了TILE/SLICE結構,而tile是並行處理的,另外也不能跨SLICE,因此當前CTB只有和left/TOPCTB處於同一個tile/SLICE時才能共享SAO參數。
總結: SAO是一在deblocking后的一個后處理步驟,會影響到interprediction的參考幀值。SAO是對重構像素進行了PSNR提升的一個重要步驟,直接對luma/chroma值進行非線性操作。H265SAO做的tradeoff就是首先對CTB中的pixel進行分類,再對每一個類別分別進行處理,這樣避免了對每一個pixel直接進行處理帶來的高碼率的代價,從而轉換成了對分類后的類進行的處理,而分類的類別的數目是比較少的,對於bandoffset和edge offset都是4個類別。因此只是需要提供4個offset值就足夠。
三、編碼算法處理過程:
一張圖片會被切割成多層的四元樹區域,為了決定取樣自適應偏移的系數,下列為處理的過程:
1. 根據圖片大小,決定最大四元樹階層L。2. 分割圖片至最小四元樹階層L的區域。3. 從每一最小區域收集所有取樣自適應偏移的類型統計資料。4. 使k = L。5. 導出每一區域階層為k的取樣自適應偏移型態參數。6. 選出位元率-失真(Rate-Distortion)最小的取樣自適應偏移型態。7. 結合每一階層為k-1的父區域和階層為k的子區域的統計資料。8. 對於每一階層為k-1的父區域,根據失真率而決定是否合並階層為k的子區域。9. 使k = k – 1 ,若k大於0則跳至步驟5繼續,否則結束。
以下說明如何從取樣自適應偏移編碼器的四元樹切割得到統計資料,Nl,i,t,c為在階層l、區域i、類t、型態c的像素數目,al,i,t,c為相對應的偏移,el,i,t,c為相對應原始訊號和重建訊號差的合,Rl,i,t為相關偏移的預測率,借由使用收集到的統計資料,可以利用簡單的式子計算出預測的失真減少量,Dl,i,t為階層l、區域i、類t、型態c的預測失真減少量。
Dl,i,t =
(Nl,i,t,ca2l,i,t,c - 2al,i,t,cel,i,t,c) (1)
得知預測失真減少量之后,我們可以計算出位元率-失真成本(Rate-Distortion-Cost),λ為拉格朗日乘數。
Jl,i,t = Dl,i,t + λRl,i,t (2)
編碼器會根據式子(4)選擇有最低位元率-失真成本且在階層l、區域i的類,T為取樣自適應偏移類的集合。
Jl,i =
(Jl,i,t) (3)
tl,i =
(Jl,i,t) (4)
得到最低位元率-失真成本以及最佳取樣自適應偏移類之后,編碼器會嘗試合並子區域成一個父區域,J’l,t和t’l,i分別是合並后的位元率-失真成本以及選擇的取樣自適應偏移類,Ωl,i是階層l和區域i的集合。
J'l,i =
(
Jl+1,k,Jl,i) (5)
t'l,i =
(
Jl+1,k,Jl,i) (6)
根據合並子區域后的結果,相關父區域的分離資訊由以下公式決定:


Sl,i為1代表當前區域會被切割成若干個子區域,為0則代表當前區域不會被切割,處理所有階層k的區域后,編碼器會繼續處理階層k-1的區域直到階層0的區域,最后使用決定的取樣自適應偏參數更新每一區域的解碼器圖像緩沖區。
四、其他說明:
1、 其他部分說明參考Paper:Sample Adaptive Offset in the HEVC Standard
對於一個CTU,關於EO、BO和no SAO的決策,參見論文Fast Distortion Estimation部分,同樣對於EO的offset值選擇也參考這一部分。基本思想就是通過RDO進行嘗試。
對於EO的offset值,由於SAO是在DF之后,所以在DF過程中,可以順便產生很多SAO中會用到的值,其中EO的可能的offset值也可以在這個過程中產生,然后在附近的幾個值進行RDO。
2、關於限制EO的offset的正負和將BO傳輸band offset的數目從16減到4個的說明和原因,參見Paper:IMPROVED SAMPLE ADAPTIVE OFFSET FOR HEVC
