蝶形算法(H.264)
視頻編碼 2009-10-27 09:01:15 閱讀379 評論0 字號:大中小 訂閱
爲什麼要進行變換
空間圖像數據通常是很難壓縮的:相鄰的採樣點具有很強的相關性(相互關聯的),而且能量一般平均分佈在一幅圖像中,從而要想丟掉某些數據和降低數據精度而不明顯影響圖像質量,就要選擇合適的變換,方法,使圖像易於被壓縮。適合壓縮的變換方法要有這樣幾個性質:
1、可以聚集圖像的能量(將能量集中到少數有意義的數值上);如下圖:
舉個例子說明,下圖是變換前的數據:
以下是變換後的數據:
可以看出,經變換後,數據的能量基本上集中到左上方(低頻信號)了,而變換後的數據完全可以通過反變換還原成原來的數據。爲了達到壓縮文件的目的,我們就可以丟棄掉一些能量低的數據(高頻信號),而對圖像質量影響很小。
2、可以除去數據之間的相關性(以使丟掉不重要的數據對圖像的質量影響很少)。
3、變換方法應該適合用軟硬件實現。
以下將描述4x4整數DCT推導過程
將上面的DCT公式轉變爲矩陣形式,爲了說明標準中整數變換和反變換,先設d=c/b,
我們可以把DCT變換寫成下式:
其中,爲了保證正交,a ,b, c, d的值可分別如下設置:
根據假設,上式可化爲:
把兩邊的對稱矩陣移到左邊可得:(下一步運算沒搞清楚是怎麼回事。)(對角陣移項)
這一步也有點問題:(等價的乘數移項)
此時,d的值爲0.4142。這樣的話,還是實數運算。如我們令d=1/2,則b=sqrt(2/5).
c=sqrt(1/10),同樣,可以保證矩陣的正交,同時,可以把運算變爲整數運算。
1/2可以提到矩陣外面,並與右邊的點乘合併,得
其中,
在JM編碼器中,變換過程只包括了
後面的點乘實際上是在量化過程中進行,因爲後面的點乘還有實數運算,實數運算將不可避免地產生精度誤差,而且運算量巨大。而量化本身就會丟失一些信號,因些,這些實數運算放在量化過程中將大大的降低變換的運算率同時又不明顯影響精度?
然而,4X4的矩陣運算如果按常規算法的話仍要進行64次乘法運算和48次加法,這將耗費較多的時間,於是在H.264中,有一種改進的算法(蝶形算法)可以減少運算的次數。這種矩陣運算算法構造非常巧妙,利用構造的矩陣的整數性質和對稱性,可完全將乘法運算轉化爲加法運算。
變換過程在JM中代碼實現如下:
// Horizontal transform水平變換,其實就是左乘Cf,
for (j=0; j < BLOCK_SIZE && !lossless_qpprime; j++)
{
for (i=0; i < 2; i++)
{
i1=3-i;
m5[i]=img->m7[i][j]+img->m7[i1][j];
m5[i1]=img->m7[i][j]-img->m7[i1][j];
}
img->m7[0][j]=(m5[0]+m5[1]);
img->m7[2][j]=(m5[0]-m5[1]);
img->m7[1][j]=m5[3]*2+m5[2];
img->m7[3][j]=m5[3]-m5[2]*2;
}
// Vertical transform垂直變換,其實就是右乘CfT
for (i=0; i < BLOCK_SIZE && !lossless_qpprime; i++)
{
for (j=0; j < 2; j++)
{
j1=3-j;
m5[j]=img->m7[i][j]+img->m7[i][j1];
m5[j1]=img->m7[i][j]-img->m7[i][j1];
}
img->m7[i][0]=(m5[0]+m5[1]);
img->m7[i][2]=(m5[0]-m5[1]);
img->m7[i][1]=m5[3]*2+m5[2];
img->m7[i][3]=m5[3]-m5[2]*2;
}
上面的內容載抄自網絡,我做了少量更改。多數內容來自畢厚傑的書。
這裏來分析一下蝶形算法,這個蝶形算法和一般FFT的蝶形算法不同,由於我沒有找到相關論文,能找到的書和網絡資料又語焉不詳,只好自己推導。上面的JM代碼就是計算下面三個4x4矩陣的過程。
分析一下前兩個矩陣的乘法,只分析他們結果矩陣的第一行。有什麼辦法可以減少運算量呢?首先採用傳統方法計算,得到結果:
X[0] = x[00]+x[10]+x[20]+x[30]
X[1] = 2*x[00]+x[10]-x[20]-2*x[30]
X[2]= x[00]-x[10]-x[20]+x[30]
X[3] = x[00]-2x[10]+2x[20]-x[30]
計算代價是16次乘法12次加法,考慮到矩陣的1的乘法可以省略,去除8個乘1,還需要8次乘法和12次加法。那麼我們再仔細思考他們的相關性,從一般算法意義上來說,可以用空間代價換時間代價,比如設置中間變量來減少計算次數。用不同的顏色把需要重複運算的部分標上,作爲中間變量。
X[0] = x[00]+x[10]+x[20]+x[30]
X[1] = 2*x[00]+x[10]-x[20]-2*x[30]
X[2]= x[00]-x[10]-x[20]+x[30]
X[3] = x[00]-2x[10]+2x[20]-x[30]
那麼提取出來的中間變量將是:
x[00]+x[30]
x[00]-x[30]
x[10]+x[20]
x[10]-x[20]
存儲了這四個中間變量,我們對比看看蝶形圖,和圖中第一層的算式相符合。用這些中間變量來組合,就可以把最終的X[0]..X[3], 計算出來。這樣,就把運算量降低到2個乘法和8個加法,剩餘的運算就是疊代這個算法。
所以,可以得出以下結論:
- 這個蝶形圖和一般意義的FFT或FDCT蝶形圖不同,是對H.264在整數DCT基礎上的具體算法優化,只對於以上Cf矩陣。
- 計算過程是把上面的三個4x4矩陣乘法分成兩兩矩陣相乘。再把殘差矩陣和後來的中間結果Cf x X一行行分別輸入蝶形圖進行一維整數DCT計算。
- 蝶形圖優化思想就是提取矩陣的相關部分,定義中間變量,減少運算次數。