為什么要有幀內(nèi)預(yù)測(cè)?因?yàn)橐话銇碚f倔监,對(duì)于一幅圖像直砂,相鄰的兩個(gè)像素的亮度和色度值之間經(jīng)常是比較接近的菌仁,也就是顏色是逐漸變化的,不會(huì)一下子突變成完全不一樣的顏色静暂。而進(jìn)行視頻編碼济丘,目的就是利用這個(gè)相關(guān)性,來進(jìn)行壓縮洽蛀。
很好理解摹迷,存儲(chǔ)一個(gè)像素的亮度值可能需要8個(gè)bit,但是如果相鄰的兩個(gè)像素變化不大郊供,我存儲(chǔ)一個(gè)像素的原始值峡碉,以及第二個(gè)像素相對(duì)第一個(gè)像素的變化值,那么第二個(gè)值我可能用2個(gè)bit就夠了驮审,這就節(jié)約了很多的空間鲫寄。而節(jié)約存儲(chǔ)消耗的bit數(shù),也就是節(jié)約碼率疯淫,貫穿了H.264編碼器的所有過程地来,不管是幀內(nèi)預(yù)測(cè)、幀間預(yù)測(cè)熙掺、變換未斑、量化、熵編碼币绩,一切的一切都是為這個(gè)目的服務(wù)的蜡秽,明白了這一點(diǎn)府阀,我們就能輕易的理解H.264編碼器,所有看上去復(fù)雜難懂的地方芽突,都是為了一個(gè)目的——節(jié)約碼率肌似。
說回到幀內(nèi)預(yù)測(cè),幀內(nèi)預(yù)測(cè)的流程見下圖
首先诉瓦,是上圖中藍(lán)色的部分川队,假設(shè)現(xiàn)在我需要對(duì)一個(gè)像素X進(jìn)行編碼,在編碼這個(gè)像素之前睬澡,先假設(shè)我已經(jīng)有一個(gè)參考像素X'了固额,這個(gè)參考像素與同一幀的臨近像素有關(guān),根據(jù)參考像素X'的值煞聪,我得到了一個(gè)預(yù)測(cè)值Xp斗躏。
然后,是上圖中紅色的部分昔脯,我用編碼的像素X減去預(yù)測(cè)值Xp啄糙,得到了殘差d,這個(gè)殘差d代替原始值X被編碼進(jìn)最終的圖像云稚,起到了節(jié)省碼率的作用
最后隧饼,是上圖中黑色的部分,殘差d和預(yù)測(cè)值Xp相加静陈,得到了X'燕雁,用于下一個(gè)像素的預(yù)測(cè)。
總結(jié)起來就是三步:
1鲸拥、以同一幀圖像內(nèi)的臨近像素作為參考拐格,計(jì)算預(yù)測(cè)值Xp
2、原始值X和預(yù)測(cè)值Xp的差值d刑赶,被傳遞到解碼端
3捏浊、解碼端接收到差值d,將其與預(yù)測(cè)值Xp相加撞叨,就得到了“原始值”X'金踪,X'=Xp+d
步驟很簡(jiǎn)單,但是里面有幾個(gè)問題要明確谒所,首先要知道的是热康,我們固然可以按像素來進(jìn)行預(yù)測(cè),但是這樣太費(fèi)事了劣领,要計(jì)算很多次姐军,而且由于幀內(nèi)預(yù)測(cè)的特性,你要預(yù)測(cè)當(dāng)前的像素,能參考的像素只能是它的臨近像素奕锌,也就是前面已經(jīng)編碼完成的著觉,它后面的像素還沒有編到,所以自然是不能用來編碼當(dāng)前像素的惊暴,因此我們只能一個(gè)像素一個(gè)像素進(jìn)行編碼饼丘,編完了一個(gè)才能編下一個(gè),這樣顯然會(huì)很慢辽话。于是H.264標(biāo)準(zhǔn)中提出按塊進(jìn)行計(jì)算肄鸽,一個(gè)宏塊是16x16像素,然后它可以分成子塊油啤,最小是4x4的(這個(gè)大小是對(duì)于亮度編碼而言典徘,至于色度編碼,4:2:0格式的色度宏塊的長和寬都是亮度宏塊的一半)益咬,這樣也能大大提高計(jì)算速度逮诲。因此下面提到的“值”可以代表“像素”也可以代表“塊”,從原理上來說是一樣的幽告,而實(shí)際采用的是“塊”梅鹦,因此我也就統(tǒng)一用塊這個(gè)詞了。
我們從上面三個(gè)步驟從頭開始一點(diǎn)點(diǎn)找問題
1冗锁、這個(gè)參考值X'是怎么來的齐唆?答案是在第三步里,使用Xp和傳遞過來的殘差d相加得到的蒿讥,這個(gè)X'用于后面的塊編碼時(shí)的參考蝶念。
2抛腕、預(yù)測(cè)值Xp是怎么從X'獲得的芋绸?答案是根據(jù)X',通過某個(gè)公式計(jì)算得到的担敌。而這個(gè)X'并不是只有一個(gè)塊摔敛,而是有左側(cè)、左上全封、正上马昙、右上一共四個(gè)塊作為參考。
3刹悴、上面提到的這個(gè)某個(gè)公式是什么行楞?根據(jù)白皮書,Intra(幀內(nèi)預(yù)測(cè))有兩種土匀,一種是4x4大小的亮度塊子房,一種是16x16大小的亮度塊。
對(duì)于4x4大小的亮度塊,我們有9種預(yù)測(cè)模式证杭,如下圖所示
對(duì)于預(yù)測(cè)模式0(vertical)田度,當(dāng)前塊的十六個(gè)像素值,完全由其上方塊最后一行的那四個(gè)像素值決定解愤,第一列所有的Xp值都等于A镇饺,第二排都等于B,以此類推送讲。預(yù)測(cè)模式1(horizontal)也是一樣奸笤,完全由圖中IJKL四個(gè)像素值決定。
對(duì)于預(yù)測(cè)模式2(DC)哼鬓,則十六個(gè)像素值完全相等揭保,等于ABCDIJKL這八個(gè)像素的平均值。
對(duì)于預(yù)測(cè)模式3-8魄宏,傾斜方向的秸侣,各個(gè)像素是由A到L像素通過權(quán)重不等的公式加權(quán)計(jì)算的
比如對(duì)于模式3(diagnal down-left)來說,a=(A+2B+C+2)/4宠互,這里+2代表四舍五入味榛,b和e=(B+2C+D)/4,cfi=(C+2D+E+2)/4予跌,dgjm=(D+2E+F+2)/4搏色,hkn=(E+2F+G+2)/4,lo=(F+2G+H+2)/4券册,p=(G+2H+H+2)/4=(G+3H+2)/4
對(duì)于模式4(diag down-right)频轿,加權(quán)系數(shù)也是(1,2,1)/4,afkp用IMA三個(gè)像素計(jì)算烁焙,以此類推
對(duì)于模式5(vertical right)航邢,aj=(M+A+1)/2,同理bk是AB均值骄蝇,cl是BC均值膳殷,d是CD均值(因?yàn)檫@幾個(gè)像素延長線都不在預(yù)測(cè)用的13個(gè)像素里面)。en在M的延長線上九火,所以等于(I+2M+A+2)/4赚窃,同理fo\gp\h\i\m都可以計(jì)算出來
同理模式6、7岔激、8也基本跟5一樣勒极,注意對(duì)于模式8來說,klmnop四個(gè)像素都等于L虑鼎,因?yàn)槠溲娱L線在L的下面和前面辱匿,沒有可以平均的像素冀惭,于是只好用L一個(gè)值代替了。
還有一點(diǎn)要注意的是掀鹅,這里面A到L的像素有的沒有怎么辦散休?對(duì)于模式2(DC),有什么用什么乐尊,反正是求均值就對(duì)了戚丸。其余的模式就必須用到的那幾個(gè)像素都存在才行(EFGH四個(gè)像素可以不存在,此時(shí)認(rèn)為都等于D)
最終扔嵌,我們要選擇哪種模式進(jìn)行預(yù)測(cè)限府?為了在后面節(jié)約碼率考慮,當(dāng)然是預(yù)測(cè)的越準(zhǔn)越好痢缎,也就是選擇Xp和X'差距最小為好胁勺。而評(píng)判這個(gè)差距其實(shí)也有好幾種算法,比如SAD独旷、SATD等署穗,等到了變換那里再詳細(xì)說∏锻荩總之我們用一個(gè)公式把上面9種模式的預(yù)測(cè)都評(píng)價(jià)了一番案疲,選出里面最好的一種,作為4x4幀內(nèi)預(yù)測(cè)的選擇麻养。
我們注意到這里有9種模式褐啡,之后要進(jìn)行編碼的話,我們除了把殘差編進(jìn)去鳖昌,總得知道我預(yù)測(cè)的時(shí)候用了哪種模式吧备畦,9這個(gè)數(shù)就尷尬了,因?yàn)閯偤萌齻€(gè)比特可以表示8種许昨,四個(gè)比特可以表示16種懂盐,所以3bit不夠4bit又浪費(fèi)了。怎么辦呢车要?有個(gè)方法就比較巧妙允粤,我有1bit用來表示我當(dāng)前用的模式和前面的是不是一樣的,因?yàn)榻?jīng)常有這樣的情況翼岁,我前面塊用的預(yù)測(cè)方向和現(xiàn)在這個(gè)塊用的預(yù)測(cè)方向一樣(比如物體邊緣是一條直線,那么對(duì)應(yīng)的那幾個(gè)塊用的預(yù)測(cè)方向很可能都是一樣的)司光,如果一樣琅坡,我只用1bit就足夠存儲(chǔ)了,如果不一樣残家,我再用用4個(gè)bit存儲(chǔ)榆俺,也就達(dá)到了節(jié)約bit的目的。
說完了4x4的亮度塊,我們看看16x16大小的亮度塊茴晋。16x16亮度塊有四種模式陪捷,如下圖
前面三種很好理解了,重點(diǎn)是第四種plane的計(jì)算方式诺擅,從圖上看大概能理解市袖,不過具體算法我還不是很理解。
我們假設(shè)左上角起烁涌,上方那一行是17個(gè)像素是a1 b2 c3 d4 e5 f6 g7 h8 i9 j8 k7 l6 m5 n4 o3 p2 q1苍碟,用這17個(gè)像素計(jì)算一個(gè)H值。
我在上面標(biāo)了1~9~1的數(shù)字撮执,有數(shù)字相同的8對(duì)像素微峰,后面計(jì)算的時(shí)候,都是一對(duì)對(duì)的計(jì)算的抒钱。
i9;j8 - h8;k7 - g7;l6 - f6;m5 - e5;n4 - d4;o3 - c3;p2 - b2;q1 - a1蜓肆,這九對(duì)分別乘以權(quán)重0到8(也就是i9這個(gè)像素沒有用到),而最左邊和最右邊兩個(gè)像素權(quán)重最大谋币。
同理V值症杏,也是一樣的算法,從上到下像素記作帶'的(當(dāng)然a1' = a1)瑞信。
然后計(jì)算一個(gè)A值厉颤,它等于右上角(q1)和左下角(V值計(jì)算時(shí)候?qū)?yīng)的那個(gè)q1')的和乘以16
計(jì)算一個(gè)B值,它等于(5*H+32)/64凡简,計(jì)算一個(gè)C值逼友,C=(5*V+32)/64,這種后面加了32又除以64的秤涩,其實(shí)都是用來四舍五入的帜乞。
然后就能計(jì)算我們的預(yù)測(cè)值了。
i00 = A - 7*B -7*C + 16
pix[0][0] = i00 / 32(超出0到255范圍的要截?cái)喑?或者255)
然后計(jì)算第一行十六個(gè)像素分別是i00 + B到i00 + 15*B筐眷,然后除以32(然后截?cái)嗟?~255)
第二行是在第一行基礎(chǔ)上加了一個(gè)C黎烈,一直到第16行,加了15個(gè)C匀谣,于是這256個(gè)像素都算出來了照棋。
這就是plane方式的算法。算出來結(jié)果就跟下圖一樣武翎。
對(duì)于色度塊是亮度塊的四分之一烈炭,也就是8x8的,那就只有一種了宝恶,預(yù)測(cè)模式也跟亮度16x16塊的類似符隙,有四種趴捅,只不過具體的序號(hào)不一樣而已。是0代表DC霹疫,1代表horizontal拱绑,2代表vertical,3代表plane丽蝎。
plane的算法和上面16x16的類似猎拨,只不過系數(shù)變了,而且兩個(gè)色度塊用的方式一定都是一樣的征峦。
好了迟几,我們回到前面的幀內(nèi)預(yù)測(cè)的步驟,還有幾個(gè)問題沒有解決
4栏笆、重建值X'和原始值是不是一樣的类腮?答案是不一樣,因?yàn)閐在傳到解碼端的過程中經(jīng)過了量化蛉加、變換蚜枢、反變換和反量化,有了精度的損失针饥,因此Xp+d得到的X'跟原始的X是不一樣的厂抽。這也是為什么要用重建值X'來得到Xp而不是用原始值X。因?yàn)榻獯a器那邊在解碼圖像的時(shí)候丁眼,用到的是有損的X'獲得Xp筷凤,如果編碼器用無損的X來得到Xp的話,那么得到的殘差d在編碼側(cè)和解碼側(cè)就不一致了苞七,這個(gè)誤差擴(kuò)散到了下一個(gè)塊里藐守。
好了,這樣上面的步驟就組成了一個(gè)循環(huán)蹂风,可以一直編碼下去了卢厂,當(dāng)然最開始沒有參考的那個(gè)塊,其預(yù)測(cè)值Xp又是怎么來的呢惠啄?可以有一種方式叫做DC128慎恒,也就是認(rèn)為這個(gè)塊的每個(gè)像素都是0x80,然后依據(jù)此來計(jì)算撵渡。
實(shí)際上對(duì)于一個(gè)16x16的宏塊融柬,上面這個(gè)16x16的四種模式和它16個(gè)子塊(大小4x4)的9種模式都會(huì)算一遍,然后用16個(gè)子塊的SATD最小值和16x16的四種模式的SATD最小值比較姥闭,選擇更小的那個(gè)丹鸿,所以這里面計(jì)算量還是很大的。x264源代碼里有很多節(jié)約計(jì)算量的設(shè)計(jì)棚品,不過這些就得看代碼了靠欢,白皮書里面是沒有的,以后再做研究铜跑。
另外x264里面還有Intra8x8亮度塊的模式门怪,這種我認(rèn)為應(yīng)該也是為了找到一個(gè)預(yù)測(cè)最準(zhǔn)的模式而加進(jìn)去的,而且也不常用锅纺,所以也就不多介紹了掷空。
回過頭來看最開始的那個(gè)步驟圖,跟白皮書里給的編碼器流程圖囤锉,是不是正是編碼器的一部分呢坦弟?