視頻編碼質量評價


導語git


視頻已經成爲咱們現代生活中不可或缺的元素,衆所周知,視頻的原始數據量大的驚人,不利於存儲和傳輸!因而乎有了視頻編碼,不一樣的編碼器,不一樣的參數,軟件與硬件,到底哪種編碼編的好呢?因而乎就有了視頻編碼質量評價!一塊兒來看看!
github


本文框架web





正文算法



視頻編碼質量評價,主要分爲主觀評價和客觀評價!主觀評價主要是肉眼所見對編碼後的視頻質量給出評價!客觀評價主要利用一些統計學的概念來評價視頻編碼的質量。編程






主觀評價微信


主觀評價,顧名思義,就是人眼主觀上對編碼後的視頻的感覺,進而給出的評價!帶有必定的主觀性,只有在畫面質量明顯不一樣時才能給出比較合理的評價!以下圖,左邊的圖明顯會比右邊的畫面質量要差一些(舒適提示,雙擊圖片,點擊查看效果哦):框架




大部分時候,畫面質量在人眼看來差異並非很大,以下面的兩張圖,這樣也就沒法合理的評判畫面質量!機器學習



因而乎,頗有必要的客觀評價就出現了。ide






客觀評價svg



客觀評價主要是基於一些統計學的特性,衡量不一樣編碼器編碼以後產生的圖像,哪一些質量更好!主要有PSNR,SSIM,BD-Bitrate/BD-Psnr以及Vmaf。


PSNR


PSNR,英文全稱peak signal to noise ratio,中文譯做峯值信噪比!一般圖像通過壓縮以後,在某種程度上會與原始圖像不一樣。爲了衡量通過編碼後的圖像的品質,一般會參考psnr來衡量編碼質量是否可以使人滿意!



PSNR的計算公式以下:



咱們看到公式中,包含MSE和n,n表示編碼時採用的bit深度,如8bit的狀況下n爲8,10bit的狀況下n爲10;MSE表示編碼後圖像與原始圖像的均方差(方差的平均數),MSE的定義以下:




從統計學來說,方差表示波動性,方差越小,表示波動越小,越穩定,psnr的計算公式中,將方差做爲分母,而後再取對數,所以psnr的值越高越好。

psnr計算結果的單位爲dB,其值越高,表示畫面質量越好!

通常,psnr值高於40dB,表示畫面質量極好,(很是接近於原始圖像);

psnr值在30dB-40dB之間,表示畫面質量較好(有失真但可接受);

psnr值在20dB-30dB之間,表示畫面質量差;

psnr值小於20db表示畫面不可接受!


咱們經過編程模擬一下這個過程(這裏使用c語言模擬)


#include <math.h>

uint8_t src[3][3] = {
    7, 6, 4,
    4, 3, 5,
    5, 8, 6
};

uint8_t dst[3][3] = {
    7, 7, 5,
    4, 2, 5,
    4, 8, 5
};


double cal_mse(int src[m][n], int dst[m][n])
{
    double mse = 0.0;
    int i = 0, j = 0;
    for (i = 0; i < m; i++)
    {
        for(j = 0; j < n; j++)
        {
            int tmp = dst[i][j] - src[i][j];
            mse += (tmp * tmp);
        }
    }
    
    return mse/m/n;
}

double cal_psnr(double mse, uint8_t bit_depth)
{
    double psnr = 0.0;

    psnr = 10 * log(10, (pow(2, bit_depth) - 1) * (pow(2, bit_depth)) / mse);
    return psnr;
}


實際上,強大的FFmpeg也能夠完成這個任務!


ffmpeg -s 1920x1080 -i src.yuv -s 1920x1080 -i dst.yuv -lavfi psnr="stats_file=psnr.log" -f null –


筆者測試的編碼過程計算後的結果以下:
mse_avg:1.00 
mse_y:1.26 mse_u:0.49 mse_v:0.47 
psnr_avg:48.12 
psnr_y:47.12 psnr_u:51.19 psnr_v:51.37

看起來編碼的效果還不錯!

注:dst.yuv文件爲src.yuv編碼後的重建幀(編碼以後再解碼)

SSIM


PSNR指標比較經常使用,可是不能體現編碼先後圖像之間的相關性,而SSIM能夠從亮度,對比度和結構三個方面來描述編碼先後圖像之間的相關性。



亮度相關性

對離散信號,咱們用均值做爲亮度預測的估計值。均值的計算方式以下:


float cal_average(uint8_t src[m][n])
{
    int i = 0, j = 0;
    int sum = 0;
    for(i = 0; i < m; ++i)
    {
        for(j = 0; j < n; ++j)
        {
            sum += src[i][j];
        }
    }

    return sum / m / n;
}


基於兩個圖像的均值,定義一個亮度對比函數以下:



對比度相關性

計算圖像的標準差,計算方式以下:


float cal_varianece(uint8_t src[m][n])
{
    int i = 0, j = 0;
    double var = 0.0;
    float avg = cal_average(src);
    for(i = 0; i < m; i++)
    {
        for(j = 0; j < n; j++)
        {
            var += pow((src[i][j] - avg), 2);
        }
    }

    return var / m / n;
}

float cal_standard_deviation(uint8_t src[m][n])
{
    return sqrt(cal_varianece(src));
}


標準差能夠用做對比度估量值。基於標準差定義一個對比度對比函數以下:



結構相關性

利用兩幅圖像之間的協方差,能夠定義一個結構對比函數以下:



其中:



對於亮度,對比度,結構都有了對比函數以後,能夠最終定義SSIM的實現,SSIM定義以下:



如此定義的SSIM,表示了圖像的亮度,對比度以及結構的相關性,若是爲1表示徹底一致;

對於原始圖像和編碼後重建的圖像按照SSIM來評價:

若是SSIM的置越接近於1,表示編碼後的圖像與原始圖像相關性更強,能夠理解爲編碼的失真更小;

若是SSIM的值越接近於0,編碼編碼後的圖像與原始圖像相關性更弱,能夠理解爲編碼的失真更大。

咱們用代碼來模擬一下這個計算過程以下:

首先是計算協方差:


float cal_cov(uint8_t src[m][n], uint8_t dst[m][n])
{
    float sum = 0.0;

    float avg_src = cal_average(src);
    float avg_dst = cal_average(dst);

    for(int i = 0; i < m; i++)
    {
        for(int j = 0; j < n; j++)
        {
            sum += (src[m][n] - avg_src)(dst[m][n] - avg_dst);
        }
    }

    return sum / (m * n - 1);
}


有了協方差以後,咱們就能夠來總體的計算SSIM的值了,以下:


float cal_ssim(uint8_t src[m][n], uint8_t dst[m][n])
{
    uin8_t depth = 8;
    float L = pow(2, depth) - 1;
    float C1 = pow(0.01 * L, 2);
    float C2 = pow(0.03 * L, 2);
    float C3 = C2 >> 1;

    float avg_src = cal_average(src);
    float avg_dst = cal_average(dst);

    float var_src = cal_varianece(src);
    float var_dst = cal_varianece(dst);

    float deviation_src = cal_standard_deviation(src);
    float deviation_dst = cal_standard_deviation(dst);

    float cov_xy = cal_cov(src, dst);
    // 亮度對比函數
    float l_xy = (2 * avg_src * avg_dst + C1) / (pow(avg_src, 2) + pow(avg_dst, 2) + C1);
    // 對比度對比函數
    float c_xy = ( 2 * deviation_src * deviation_dst + C2) / (pow(deviation_src, 2) + pow(deviation_dst, 2) + C2);
    // 結構對比函數
    float s_xy = (cov_xy + C3) / (deviation_src * deviation_dst + C3);

    return l_xy * c_xy * s_xy;
}


一樣,藉助FFmpeg咱們也能夠實現ssim的計算,命令以下:

ffmpeg -s 1920x1080 -i src.yuv -s 1920x1080 -i dst.yuv -lavfi ssim="stats_file=ssim.log" -f null -
筆者測試的文件ssim的結果以下:
Y:0.987967 U:0.993548 V:0.993861
All:0.989880

BD-Bitrate/BD-Psnr


psnr和ssim分別描述了編碼的信號噪聲比和編碼後圖像與原始圖像之間的類似度,但這依然還不夠,咱們來看一種狀況。


編碼的過程常常要在質量和碼率之間取得一個很好的平衡,質量越高感官越好,可是碼率隨着也會水漲船高,帶寬對當前的視頻行業而言依然是一個巨大的成本。

評價編碼質量,假設psnr上升了,同時碼率也降低了,這個時候是咱們夢寐以求的場景;但是若是psnr上升了,而碼率也隨着上升了,這個時候就須要權衡更注重質量,仍是更但願節約帶寬而犧牲帶寬。隨之而來的問題也就來了,怎麼去評價這個選擇過程呢,就出現了BD-Bitrate和BD-Psnr。

BD-Bitrate就是在假定碼率的狀況下,來查看psnr的值,也就是在特定碼率下尋找更高質量的編碼;

BD-Psnr就是在假定編碼質量的狀況下,來查看比特率的值,也就是在特定編碼質量下尋找更合適的碼率。

BD-Bitrate和Bd-Psnr的計算通常經過採樣多個值(通常用3次多項式擬合,因此最少須要四個點),而後進行曲線擬合,繪製擬合曲線,獲得相應的圖表,進而進行選擇判斷。

假設咱們編碼測試後獲得以下值:
H.264 High Profile

H.264 Baseline Profile

Bitrate
PSNR
Bitrate
PSNR
686.76
40.28
893.34
40.39
309.58
37.18
407.8
37.21
157.11
34.24
204.93
34.17
85.95
31.42
112.75
31.24

咱們以Bitrate爲橫座標,psnr爲縱座標,獲得擬合曲線以下圖:

咱們以Psnr爲橫座標,bitrate爲橫座標,獲得擬合曲線以下圖:

從擬合後的曲線咱們能夠看到,當bitrate小於400的時候,在給定的比特率的前提下,編碼選擇H.264的High Profile會得到更高的編碼質量,若是bitrate大於400時,給定bitrate的狀況下,編碼選擇H.264的Baseline Profile會得到更高的編碼質量,這就是Bd-Bitrate的意義。

對於Bd-psnr,從圖中咱們能夠看到,給定psnr的狀況下,編碼選擇H.264的Baseline Profile,碼率永遠比編碼選擇H.264的High Profile要高,這既是Bd-psnr的意義。


Vmaf


Psnr/Ssim這些指標一般在編碼器內部,用於對編碼決策進行優化並估算最終編碼後視頻的質量,可是因爲這些算法衡量標準單一,缺少對畫面先後序列的整體評估(可是先後幀之間的相關性與編碼的質量息息相關),致使計算的結果不少狀況下與主管感覺不相符。



Vmaf就是解決這個問題的,vmaf全稱Video Multimethod Assessment Fusion,是大名鼎鼎的奈飛公司(Netflix)提出來的一種編碼質量評價的方法。

面對不一樣特徵的視頻源、編碼失真以及失真程度,每一個衡量指標各有優劣,奈飛經過使用機器學習算法,爲每個基本的指標分配必定的權重,「融合」爲一個最終指標,這樣就能夠保留每個基本指標的評價優點,最終獲得更精確的分數,這就是vmaf的核心理念。

vmaf選擇的基本指標主要有視覺信息保真度,簡寫爲VIF,細節丟失指標,簡寫爲DLM和運動量指標。

具體怎麼來計算vmaf呢,官方給出具體的例子,且在github上開源(點擊閱讀原文連接可跳轉到該項目):

當前該項目得到2.1k的star和464的fork,不錯的成績。該項目提供了多種計算vmaf的方式,使用命令行的方式,使用C語言庫,使用Python的方式,使用Docker的方式,以及結合FFmpeg一塊兒使用的方式,這裏演示一下命令行的方式,其餘方式,感興趣的讀者能夠詳細研究。

該項目提供的命令行可執行程序爲vmafossexec,準備原始的yuv文件和對應的編碼後重建的yuv文件,而後使用以下命令,便可計算vmaf:


vmafossexec yuv420p 576 324 src01_hrc00_576x324.yuv src01_hrc01_576x324.yuv vmaf_v0.6.1.pkl --log vmaf_output.xml --psnr --ssim  --subsample 5


命令中576,324表示視頻分辨率,--psnr和--ssim表示輸出psnr和ssim的值,--subsample表示將多少個圖片做爲一組,vmaf_v0.6.1.pkl機器學習算法所使用的的模型。

利用上述命令獲得的結果以下:

紅色框選 的部分是計算出來的psnr,ssim以及vmaf的值,vmaf的值越大,代表編碼的質量越好,先後幀之間的相關性越強,失真越小。
注:因爲vmaf計算的github項目開源,代碼及相關資源可能發生變動,請以實際最新的爲準。
關於編碼質量的評價,終於寫完了,花費很多天,原創着實不易,不謙虛的說,關於編碼質量的評價,全網貌似找不到更全的了,但願對你們有用,點個贊,點個在看,就是對做者最大的鼓勵,也很是期待你的關注和入羣,這裏是「視界音你而不一樣」,一個專講音視頻視界裏開發事的公衆號!等你!

交流羣已開啓,有須要的朋友,公衆號後臺回覆「交流羣」,獲取入羣方式!


 




掃碼關注瞭解更多

本文分享自微信公衆號 - 視界音你而不一樣(WorldOfVideoAndAudio)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索