背景與原理
1974年,K. R. Rao、N. Ahmed、T. Natarajan三位教授創立了離散餘弦變換(Discrete Cosine Transform, DCT)。在數字信號、數字圖像處理領域,離散餘弦變換的效果能夠接近理論上的最佳變換——Kahunen-Loeve變換(K-L變換)。
以下將介紹DCT的相關背景,並從算法、硬件、應用三個層面進行概述。
1807年,法國數學家、物理學家傅里葉(Jean Baptiste Joseph Fourier)提出了傅里葉變換(Fourier Transform, FT)。傅里葉變換的形式有很多種,歸一化的二維離散傅里葉變換(Discrete Fourier transform, DFT)可以寫成如下形式:
F(u,v)=NM1x=0∑N−1y=0∑M−1f(x,y)e−N2πiuxe−M2πivyf(x,y)=NM1u=0∑N−1v=0∑M−1f(u,v)eN2πiuxeM2πivy
傅里葉變換包含複數運算,其運算複雜度和存儲長度都超過實數運算。爲了簡化上述過程,同時達到更好的變換效果,餘弦變換應運而生。
從傅里葉變換到離散餘弦變換,需要一些數學理論的支持。在給定區間內滿足狄利赫裏條件的連續實對稱函數,可以展開成僅含有餘弦項的傅里葉級數。
對於定義在正實數域上的函數,可以通過偶延拓或奇延拓,滿足上述條件。但如果函數的定義域包含零點,情況則稍有些複雜。
以一個二維離散函數f(x,y)(x,y=0,1,...,N−1)爲例,對其進行偶延拓。
假如序列中不包含零點,自然按照以下方式延拓:
f(1,0)=f(−1,0),f(0,1)=f(0,−1),對稱中心爲(0,0)
由於序列中包括零點,考慮零點後的延拓方式:
f(0,0)=f(−1,0),f(0,0)=f(0,−1),對稱中心爲(−1/2,−1/2)
因此,按照上述方法延拓後,歸一化的二維離散餘弦變換可以寫成如下形式:
when(x,y)or(u,v)=(0,0)F(u,v)=N1x=0∑N−1y=0∑N−1f(x,y)cos[Nπu(x+21)]cos[Nπv(y+21)]f(u,v)=N1x=0∑N−1y=0∑N−1F(u,v)cos[Nπu(x+21)]cos[Nπv(y+21)]
when(x,y)or(u,v)=(0,0)F(u,v)=2N1x=0∑N−1y=0∑N−1f(x,y)cos[Nπu(x+21)]cos[Nπv(y+21)]f(u,v)=2N1x=0∑N−1y=0∑N−1F(u,v)cos[Nπu(x+21)]cos[Nπv(y+21)]
在傅里葉變換中,正逆變換的變換核e−N2πiuxe−M2πivy和eN2πiuxeM2πivy相差一個負號;相應的,在餘弦變換中,正逆變換的變換核cos[Nπu(x+21)]cos[Nπv(y+21)]也應相差一個負號。由於 cos(x)=cos(−x) ,所以餘弦變換的正逆變換在形式上具有一致性。
順帶一提,在某些教材上,將上述形式的離散餘弦變換寫成類似於下面的樣子:
F(u,v)=N1x=0∑N−1y=0∑N−1f(x,y)cos[2Nπu(2x+1)]cos[2Nπv(2y+1)]
也就是將21 乘入了整個分式中。雖然這樣寫只是變了一種形式,不影響結果,但破壞了原本的幾何意義(或者說偶延拓過程),誰知道這個 2x+1 對應着什麼東西。
一、DCT在算法層面的實現
爲了簡化離散餘弦變換的計算過程,需要算法上進行優化。優化可以從兩方面入手,一是降低計算次數,一是將浮點運算轉化爲整數運算。
在計算次數方面,對於N次離散餘弦變換,需要o(N2)次運算,通過快速算法,能夠將運算降低至o(Nlog2N) 次。
在整數運算方面,通過量化實現整數近似,並且在量化的同時保證變換的可逆性(不然變過去之後,就變不回來了),將離散餘弦變換過程中的浮點運算轉化爲整數運算,大致過程如下:
爲了熟悉和理解上的方便,將離散餘弦變換表達式寫成矩陣形式:
Y=CXCT所謂整數近似,並不是單純地將浮點數四捨五入或者直接截斷得到整數(這樣做後,再進行逆變換就變不回來了),而是將浮點運算歸入量化過程(在逆變換時進行反量化,保證與原始數據的一致性),讓離散餘弦變換過程僅包含整數運算。
這樣做看似是朝三暮四,但在實際應用中,量化和量化中的浮點運算是必不可少的。反正總歸是要量化,這樣可以將兩次浮點預算合併爲一次,對優化算法仍舊是有意義的。
進行量化的整合後,離散餘弦變換表達式爲:
Y=(CfXCfT)⨀Ef其中,⨀表示矩陣的點乘。完成上述整數化後,不僅將浮點運算歸入量化過程,而且可以並行計算,加快速度。
二、DCT在硬件層面的實現
我們先不談DSP等專用芯片,單說CPU與GPU。
計算機的運算可以分爲兩類,整數運算和浮點運算;浮點運算又可以分爲兩類,單精度浮點運算和雙精度浮點運算。
GPU擁有大量並行流處理器,但缺少串行邏輯控制機構,擅長進行浮點運算,對於更注重溢出檢查的整數運算,反而是GPU的弱項;CPU作爲中央處理器,則是兩種運算通吃。
進一步考慮浮點運算,單精度浮點運算的複雜度低於雙精度浮點運算。市面上常見的遊戲顯卡和TaiTan X,均是注重單精度浮點運算,而限制了雙精度浮點運算。開普勒架構的遊戲顯卡,雙精度浮點運算能力是單精度浮點運算的1/24;同時代的CPU,這一比值大約是1/2。
一般而言,對於物理建模與模擬(比如流體力學模擬、量子化學計算)、3D建模(其實也是一種意義上的物理建模),需要雙精度浮點運算;對於一般的圖形渲染(包括遊戲渲染、視頻渲染)、機器學習,需要單精度浮點運算。所以遊戲顯卡削弱雙精度浮點運算,TaiTan X一個勁提升單精度浮點運算,以及1080Ti被視爲平民機器學習神器,都是有其道理的。
回到離散餘弦變換。的確,GPU的並行運算速度超過CPU。經過優化的整數離散餘弦變換算法利於並行計算,更是突出了GPU的並行優勢,但GPU並不擅長整數運算。此外,在實際應用中,離散餘弦變換過程伴隨着串行邏輯,這也GPU不能勝任的。隨着GPU計算的火熱,如何讓GPU完成離散餘弦變換成了學界熱點。但目前來看,讓CPU扮演主要角色,把一部分運算交給GPU實現加速,應當是比較現實的考慮。
三、DCT在應用層面的實現
以視頻編碼爲例。1984年,H.261編碼標準開始研究。1990年,H.261編碼標準由國際電信聯盟(ITU-T)發佈。1993年,MPEG-1編碼標準由國際標準化組織/國際電子學委員會(ISO/IEC)發佈。自此,H.26X系列與MPEG-X系列開始了各自的更新換代,當然期間也有合作交易,比如大家可能比較熟悉的MPEG-2與大家可能不熟悉的H.262,其實是一個東西,又比如MPEG-4,包括了(早期的)MPEG-4、MPEG-4/AVC(=H.264)、MPEG-4/HEVC(=H.265)三個標準。
誒,好像就差H.263與MPEG-3沒有提。前者隨着技術的進步退出了歷史舞臺,後者則被斃掉了…
從H.261開始,離散餘弦變換就被應用於視頻編碼中。當技術發展到H.264與H.265,就具體的數學計算而言,H.261創立的分塊編碼被後續標準沿用,H.264在亮度平面上的基本分塊爲8x8像素塊,於是離散餘弦變換是這個樣子(代入N=8):
F(u,v)=161x=0∑15y=0∑15cos[8πu(x+21)]cos[8πv(y+21)]f(x,y)=161u=0∑15v=0∑15cos[8πu(x+21)]cos[8πv(y+21)]在整個編碼過程中,離散餘弦變換的作用如下:
首先,按照圖像處理的一般流程,進行採樣、整量,完成連續數據到離散數據的量化。根據前面提到的算法優化,量化過程整合了離散餘弦變換的浮點運算。
接下來,進行整數離散餘弦變換。做這一變換有什麼用?一方面,從圖像處理的整體流程而言,變換後便於後續處理;另一方面,從編碼的角度而言,變換後使圖像信息集中,在數學上體現爲描述關鍵信息的係數變少,相應的,所需存儲空間降低,達到降低視頻體積的目的。
以上博文轉載自:
- https://zhuanlan.zhihu.com/p/33845296