前言
其實我以後并不打算着重研究視訊編碼,隻是因為這次畢設選了這個題,是以稍微學了點相關的皮毛。關于FFMPEG的源碼的分析我推薦雷宵骅前輩寫的部落格,需要學習的請點選傳送門。我基本是看着他的部落格學的,雖然現在ffmpeg版本有一定更新,但是大體架構基本是不變的,題目中需要用到的并且和他的部落格中寫的不同的我會稍微提一下。關于其他ffmpeg源碼的研究如果沒有特殊需要,我基本是不會考慮做的。最後,如果我有寫錯,歡迎指正。
正文
關于實作隐寫算法我打算分兩篇來寫,這篇寫鋪墊一下理論知識,下一篇從代碼實作角度上講
1. 關于H.264編碼的相關知識
關于H.264是什麼東西這種問題這裡就不多贅述了。我們直接講一點幹貨。
1.1 I幀 P幀 B幀 與 GOP
任何一個視訊,都可以看做是一個圖檔流,對于視訊中每一張圖檔,我們一般稱作幀。H.264格式視訊流中的幀一般分為3類,即I幀,P幀,B幀(好像還有其他類别的幀,可以用于處理非常特殊的圖檔,這裡不展開講了)。這三類幀分别用不同的政策來壓縮一張圖檔,進而降低視訊大小。
從資訊論的角度來講,資料可以壓縮是因為資訊存在備援,資訊備援存在的條件要麼是出現頻率不均等,要麼是資料間存在相關性。對于出現頻率不均等的資料我們可以運用熵編碼(如哈夫曼編碼)的手段将資料壓縮;對于資料間存在相關性這個問題隻能根據具體問題,試圖将相關的資料轉化成出現機率不均等的的資料。是以視訊編碼的核心就是挖掘視訊畫面中所有像素點之間的相關性。當然在必要時,也可以制造一些肉眼不可見的相關性進一步壓縮。(比如直接砍去畫面中高頻分量)
了解了這點之後就比較容易了解這三種幀了:I幀主要挖掘單個畫面中的像素點的相關性,P幀挖掘目前畫面與前一個畫面之間的相關性,B幀挖掘目前畫面與前後兩個畫面之間的相關性。乍一眼看下去好像B幀比P幀厲害,也确實B幀的壓縮率會比P幀更高(因為相關性挖掘更充分),但是在實時視訊傳輸的過程中往往是不采用B幀的。
I幀相當于單張圖檔壓縮,也是相關性挖掘最不充分的。同樣一個畫面用I幀會比用P幀和B幀壓縮率低非常多!但是I幀也有個非常明顯的優勢:不受其他幀的幹擾。由于P幀和B幀需要參考前後的幀,是以如果視訊流中如果連續非常多的P幀與B幀,到後面的畫質會大打折扣。這個時候我們就需要一個I幀來矯正前面的誤差,使誤差不繼續向後傳遞。是以實際應用中,H264碼流中的視訊幀往往是按照三種幀的某一個排列不斷重複。
比如:IPPPPPPPPPIPPPPPPPPPIPPPPPPPPP......... 或:IBPIBPIBPIBPIBP.......
前一個例子是IPPPPPPPPPP這樣的幀結構不斷重複,後一個例子是IBP這樣的幀結構不斷重複。
我們把每一個這樣的幀結構叫做畫面組(GOP),每一組中所包含的幀數叫做畫面組大小(GOP size)
1.2 RGB與YUV
對圖像有點了解的都知道一個像素點會有三個分量,如RGB。這裡我們介紹另一種次元YUV,其中Y為亮度,U和V為色度。YUV分量與RGB分量之間可以通過簡單的線性變換來實作。這樣變換并不是無意義的,實驗表明人的肉眼對YUV中Y的分量較為敏感,對UV則相對不那麼敏感。這樣我們在存儲圖檔時,可以降低U分量和V分量的分辨率。在H264編碼的視訊中,yuv通常是4:2:0的采樣,其實就是每2*2個像素共享同一個U和同一V,并分别擁有自己的Y。
在隐寫算法中由于亮度的資訊較多,編碼規則也較複雜,更具有操作空間,是以一般都在亮度分量中嵌入資訊。
1.3 I幀
我的課題基本上全部圍繞I幀展開,其他P幀和B幀是如何實作的我就不贅述了。這裡需要重新強調一下的是:I幀隻挖掘畫面内像素點的相關性。
I幀亮度分量(Y分量)處理的最大單元是一組16*16的像素點,我們把它叫做16*16宏塊。注意這裡強調的是最大單元,就是說會有更小的單元組成一個16*16宏塊,但是16*16宏塊就直接組成整個I幀了。
我們接着介紹每個16*16宏塊的處理方式。
每個16*16宏塊可能會被繼續劃分(也可能不劃分了)成4個8*8宏塊,或16個4*4宏塊。其中8*8宏塊和4*4宏塊不會繼續被劃分了。16*16不劃分的宏塊一般組成圖像較平坦的區域,4*4組成變化較快的區域,8*8則介于中間。我們通過兩張圖來對此有個較直覺的認識。
注:I幀中的宏塊不會被劃分成16*8之類的塊。
左圖為原圖,右圖為經過劃分後的圖。最左上标出的紅框大小為一個16*16宏塊的大小。
回到要我們要挖掘像素點之間相關性這一點,由于畫面之間的像素點是相關的,并且從普遍機率上說,一個像素點與其越近的相鄰像素點相關性越強,也就是說周圍的像素點可以一定程度上對一個特定像素點的值進行預測。
H264的編碼中對于不切分的16*16的宏塊一個有4中預測模式(IPM)
每種預測模式其實就是用與該宏塊相鄰的相應像素直接填充被預測的子產品。
對于8*8宏塊和4*4宏塊,H264編碼一共提供了9種IPM。對于一些邊界上的宏塊處理方法我會在後續具體分析代碼的文章中分析。
當然僅僅通過預測我們是無法得到清晰圖檔的,我們能得到的圖檔大概隻能是這樣支離破碎的。
注:第一個宏塊是灰色的是因為沒有可用于預測的像素,是以亮度直接被設為128
這張圖其實還是原圖減去殘差圖得到的,其實相當于假設用于預測的像素都是無誤差的,實際隻通過IPM是無法還原圖的。
有了IPM之後我們要做的事情就是矯正誤差,由于誤差的分布機率不同,誤差接近0的點出現頻率會明顯比遠離0的點高,于是這樣我們就可以用熵編碼壓縮圖檔了。當然,在H264具體的編碼過程中,後續還有通過DCT變換進一步消除相關性進行壓縮。
上圖是殘差圖像
在H264中,每個IPM其實也是先通過預測得到的,一般來說IPM的預測值通過緊鄰的上邊一個宏塊的IPM和左邊一個宏塊的IPM得到。該宏塊的IPM和預測的IPM相同,那麼在編碼時碼率會有一定縮小。
2. 關于幀内預測模式隐寫的相關知識與算法
2.1 隐寫
隐寫的目的就是将資訊隐藏進載體,這樣一旦載體被通訊了,被隐藏的資訊實際也被通訊了,但是卻無法被檢測到隐藏資訊通訊的發生,也就是将通信信道隐藏在載體中。舉個簡單的例子就是藏頭詩,詩是載體,而詩句的頭一個字就是被隐藏資訊。
2.2 視訊隐寫的相關評價标準
1. 信噪比:對于隐寫後的算法不能有過大噪聲,過大的圖像噪聲肉眼能明顯覺察出圖像具有顆粒感。
2. 嵌入容量:對于不用算法用于同一段視訊嵌入容量是不同的,任何方法嵌入過多資料可能會導緻視訊品質下降。
3. 比特率增加率:由于嵌入算法都是修改了原來最優方案選用次優方案替代之(不限于幀内預測模式隐寫),是以一定會導緻嵌入後的視訊流大小大于原視訊流,如果比特率增加過大,會增加原視訊傳送負擔。
2.3幀内預測模式隐寫
通過上文我們可以知道H264提供的預測模式還是比較豐富的,這就給嵌入資訊提供了空間。這裡我簡單介紹一下一篇2012年關于幀内預測模式隐寫的論文《H.264/AVC Data Hiding Based on Intra Prediction Modes for Real-time Applications》,作者為Samira Bouchama, Latifa Hamami, and Hassina Aliane。
由于肉眼對圖像的高頻資訊不是特别敏感,也就是4*4宏塊編碼的部分,是以我們一般隻對4*4宏塊實行資訊嵌入。
上面我們說到4*4宏塊一共有9中IPM,而其中有很多IPM是非常近似的,如第四種與第二種,其預測所用到的像素隻差一個像素M。于是論文就提出替換近似的預測模式來實作資訊嵌入。當然如果該宏塊的IPM與預測的IPM(MPM)相同,這個宏塊是不用來資訊嵌入的,否則會很大幅度增加編碼負擔。
論文中将IPM分為4組,修改條件是MPM不與IMP同組,并且修改後的IMP必須和最佳IMP同組
組一:1&8
組二:3&7
組三:2&4&5&6
組四:0&2
上圖是論文提出的一種修改IPM的政策,這種算法浪費了0這個IPM,即如果遇到IPM=0時,不嵌入任何資訊。
我們從解碼的角度可能能更好地了解上面這張表格
2.4 對論文算法的一些簡化
其實這篇論文的邏輯是有點複雜的,我用另一種相對邏輯簡單一點的算法對其進行簡化
對于一個宏塊的MPM,與嵌入的比特,可以對應到四個可替代的IPM,在其中選擇編碼代價最小的替代原來的最佳IPM。
可以發現,其中MPM=1與MPM=7時不完全按照大小排序,是為了保證存在與最佳IPM近似方向的IPM可供選擇。
運用這個隐寫算法最大嵌入容量會比2.3中描述算法略小,而編碼後碼率增加率也相應減少。
注:我并不知道這個算法有沒有和更早的論文撞重,好像很多關于幀内預測模式隐寫的論文都是分兩組,一組表示0,另一組表示1。
最後
關于H264和幀内預測模式隐寫就介紹到這裡,下一篇我們介紹X264與ffmpeg中對H264中I幀的的處理,然後實作2.4中描述的算法。