JPG學習筆記3(附完整代碼)

  採樣後,須要對8*8block進行DCT(離散餘弦變換)。爲何要進行DCT?第一點是餘弦變化後的圖片能量主要集中在低頻,咱們只須要保存低頻數據,默認高頻0。第二點是,DCT後的圖片很適合哈夫曼壓縮,對於原圖而言,區域相連的pixle數值差很少,哈夫曼壓縮效果差。所有代碼在 https://github.com/Cheemion/JPEG_COMPRESShtml

圖片引用自"Compressed Image File Formats JPEG, PNG, GIF, XBM, BMP - John Miano"[1]git

           

1.離散餘弦變換直覺上的認識

假設咱們有一個2*2的圖片以下,最亮表明1, 最暗表明-1。github

 咱們普通的認識是,這是一個由4個4維向量組成的一個圖片(以下)。能夠當作是一個2*2的平面向量,也能夠當作4維向量(1,0,0,0)(0,1,0,0)(0,0,1,0)(0,0,0,1)。每一個向量兩兩相交,而且都是單位向量。這4個基向量能夠獲得任何的一張2*2的圖片。ide

(1,0,0,-1) = 1 *(1, 0, 0, 0) +  0 *(0,1, 0, 0) + 0 *(0, 0, 1, 0) + (-1) * (0, 0, 0, 1);函數

離散餘弦變化,其實只是把上面的4個基向量進行了變化。以下學習

基向量變成了(0.5,0.5,0.5, 0.5)(0.5, -0.5, 0.5, -0.5) (0.5, 0.5, -0.5, -0.5) (0.5, -0,5, -0.5, 0.5),每一個向量兩兩相交,而且都是單位向量。這4個基向量能夠獲得任何的一張2*2的圖片。ui

因此DCT其實只是換了一個基向量而已。spa

左邊第一個圖爲低頻,由於整個圖的顏色沒有變化,能夠認爲變化頻率爲0code

最右邊的圖爲高頻,上下和左右的顏色都變化了一次。orm

(1,0,0,-1) =  0 *(0.5, 0.5, 0.5, 0.5) +  1 *(0.5,-0.5, 0.5, -0.5) + 1 *(0.5, 0.5, -0.5, -0.5) + 0  * (0.5, -0.5, -0.5, 0.5);

藍色的係數只要經過原圖和新的基向量點成就能夠獲得,好比向量(0.5, 0.5, 0.5, 0.5)前面的係數爲 1 * 0.5 + 0 * 0.5 + 0 * 0.5 + (-1) * 0.5 = 0;

2.離散餘弦變換公式上的認識

 DCT離散餘弦正變換

令G(i, j) = cos((i + 0.5) * pi * u /N) * cos((j + 0.5) * pi * u / N), u 和 v是constant

隨着u和v從0到7(由於咱們的block是8*8) 不斷的變化咱們能夠畫出以下圖

畫圖代碼matlab以下

function [ out ] = g( u,v )
    p = zeros(8,8);
    for i = 0:7
        for j = 0:7
            p(i + 1,j + 1) = cos((i + 0.5) * u * pi / 8) * cos((j + 0.5) * v * pi / 8);
        end
    end
    out = p;
end
matlab畫圖代碼
clc; clear; close all;
figure;
maximum = 0;
minimum = 100;
for u = 0:7
    for v = 0:7
        pp = g(u,v)
        subplot(8, 8, u * 8 + v + 1);
        imshow((pp + 1) ./ 2);
    end
end
matlab畫圖代碼主函數

乘以係數c(u)c(v)是使咱們的G(i, j)變成單位向量。公式剩餘部分就是點乘的過程。

 

 

 IDCT逆變換

3.代碼

void DCT(Block& block) {
    Block temp;
    std::memcpy(&temp, &block, sizeof(Block)); //copy from original
    //8 rows
    //DCT行變化
    for(uint i = 0; i < 8; i++) {
        double* f = &temp[i * 8]; //one dimension Array , and will perform DCT on it
        for(uint k = 0; k < 8; k++) {
            double sum = 0.0;
            for(uint n = 0; n < 8; n++){
                sum = sum + f[n] * std::cos(((n + 0.5) * M_PI * k / 8));
            }
            sum = (k == 0) ? (sum * std::sqrt(1.0 / 8)) : (sum * std::sqrt(2.0 / 8));
            block[i * 8 + k] = sum;
        }
    }
    
    std::memcpy(&temp, &block, sizeof(Block)); //copy from 
    //DCT列變化
    for(uint i = 0; i < 8; i++) {
        double* f = &temp[i]; //one dimension Array with 8 steps increment , and will perform DCT on it
        for(uint k = 0; k < 8; k++) {
            double sum = 0.0;
            for(uint n = 0; n < 8; n++){
                sum = sum + f[n * 8] * std::cos(((n + 0.5) * M_PI * k / 8));
            }
            sum = (k == 0) ? (sum * std::sqrt(1.0 / 8)) : (sum * std::sqrt(2.0 / 8));
            block[i + k * 8] = sum;
        }
    }
}

 

 以上所有的代碼在https://github.com/Cheemion/JPEG_COMPRESS/tree/main/Day3

 完結

  Thanks for reading.

   wish you have a good day.

                                                                                                                                                                                                                                                              >>>> JPG學習筆記4(附完整代碼)


 

參考資料

[1]https://github.com/Cheemion/JPEG_COMPRESS/blob/main/resource/Compressed%20Image%20File%20Formats%20JPEG%2C%20PNG%2C%20GIF%2C%20XBM%2C%20BMP%20-%20John%20Miano.pdf

相關文章
相關標籤/搜索