JPEG - 想法與實踐/雜項
在量化之後,sxs 矩陣 g(u, v) 中的最後 s2 個數字通常非常小,我們可以選擇一個數字 r = 3, 4, ..., s-1,並省略 u 或 v >= r 的那些對 (u, v),這樣我們只需要處理 r2 個數字 (u, v = 0, 1, ..., r-1)。然而,這樣做並沒有讓我們獲得太多益處,因為 r 必須非常接近 s-1,而且零的實際數量並不重要(30 個零佔用 8 位,12 個零佔用 7 位)。在繪製過程中,我們可以透過將逆餘弦變換限制在 r2 個數字來節省時間。我們在 第二部分 的(兩個)繪製程式中已經做到了這一點(我們設定 r = 6)。但由於這樣的程式(用於實際用途)必須用匯編語言編寫,因此這樣做並沒有給我們帶來太多益處,因為如今圖片繪製速度非常快。但看到我們實際上需要多少個(或者更確切地說,需要多少個)餘弦變換數字(顏色值函式展開式中的項)是有啟發性的。因此,我們設計了我們的繪圖程式,以便我們可以輸入“項數”(數字 r)。在這張圖片(使用 8x8 方格)中,項數分別是 8 和 4
-
8 項
-
4 項
請注意,檔案的大小很大程度上取決於壓縮之前大多數數字是零,因為每第二個數字都表示零的數量。因此,如果只有很少的零,那麼大多數(每第二個)這些數字(以編碼形式為 000)會不必要地佔用大量空間。因此,如果我們不是在量化時除以一個大數字,而是除以一個小數字(例如 0.1),那麼我們會發現檔案佔用空間是 BMP 格式的兩倍!
在真正的 JPEG 過程中,選擇 8 作為小方格的邊長與計算機中 8 的作用無關,因為數字被轉換為各種長度的位序列。邊長不能太小,因為這樣會減弱餘弦變換的效果,也不能太大,因為這樣計算量會太大:對於一個 sxs 方格,總的項數是 s4,因為有 s2 個點,並且每個點都有 s2 個公式。因此,如果邊長加倍,那麼計算量會增加四倍。選擇 8 作為邊長在 JPEG 過程引入時一定是最佳選擇。然而,如今,隨著速度的倍增,我們可以透過選擇更大的邊長(例如 12)來實現更好的壓縮,但改變這一點為時已晚,而且收益並不顯著。
對於之前提到的 280 畫素的二次方圖片(用於演示餘弦變換),計算量是將圖片分成 8x8 方格的 1225 倍。
在下面的兩張圖片中,我們分別使用了 20x20 和 10x10 方格的劃分。該過程對於較小的劃分效率不如較大的劃分。兩張圖片都用大約相同的數字進行量化,第一張佔用 13 Kb,第二張佔用 22 Kb
-
20x20 方格
-
10x10 方格
讓我們看看如果在下面最上面的圖片中,我們在亮度部分和色度部分的量化上做出很大的差異會有什麼結果。在最左邊的圖片中,亮度部分的質量較低,而色度部分的質量較高。因此,圖案被破壞了,但顏色看起來是正確的。在最右邊的圖片中,情況相反:圖案是正確的,但顏色不熟悉
-
原始
-
亮度部分不好
-
色度部分不好
JPEG 過程總是會引入圖片的變化,但透過選擇高品質,這些變化可以變得微不足道。但它們確實存在,如果你想將來能夠處理圖片,就不應該以 JPEG 格式儲存它。有些圖片比其他圖片更不適合 JPEG 壓縮,因為如果要使變化完全不可見,則必須將質量設定為高。但人們會說,總是有可能以 JPEG 格式儲存而不會出現可見的變化。然而,這並非一定屬實:這取決於 JPEG 的實現。我們的演示程式總是可以生成一個檔案,該檔案會導致(幾乎)無瑕疵的圖片,但這是因為我們以與 Y 分量相同的方式處理顏色分量——我們只用不同的數字進行量化,但我們可以不進行量化(將質量設定為 100)。在真正的 JPEG 過程中,可以減少兩個顏色“圖片”(顏色分量)的大小,與灰度圖片(Y 分量)相比。這可以透過(例如)先將兩個顏色“圖片”分成 2x2 方格,並將這樣一個方格視為一個畫素(取四個顏色值的平均值),從而使顏色圖片變為原來的四分之一大小。這是在分成 8x8 方格之前進行的,因此 Y 分量的四個 8x8 方格與顏色分量的單個 8x8 方格組合。原因是顏色通常不會在圖片上快速變化,我們可以透過這種方式壓縮大約 25%。該過程稱為顏色分量的子取樣。
接下來的兩張圖片是用我們(自制的,但)第二部分 中的真正的 JPEG 程式製作的,但設定不同。這張圖片是透過將每第二個畫素為綠色,其餘畫素為透明的圖片覆蓋到另一張圖片上而製作的。由於畫素到畫素之間的強烈變化,這兩張圖片都佔用了相當大的空間。在第一張圖片中,顏色分量與 Y 分量以相同的方式處理,因此圖片是正確的。在第二張圖片中,使用了顏色分量的子取樣,因此顏色值變成了平均值,因此圖片更偏綠色
-
無子取樣
-
子取樣
請注意,並非所有 JPEG 壓縮程式都允許在顏色分量的子取樣和非子取樣之間進行選擇。
對於灰度圖片,我們只有 Y 分量,但由於 Cb 和 Cr 分量(在量化之後)的貢獻相對於 Y 分量很小,因此圖片的灰度版本幾乎佔用的空間與彩色版本一樣多——通常超過 90%。
當圖片只有一種顏色時,壓縮率應該達到最大值。對於我們的演示程式來說,情況就是這樣:這樣一個 1000x1000 畫素的圖片的資料部分只佔用了 14 位元組。但是,當我們使用真正的 JPEG 過程時,資料部分將佔用 15000 位元組——我們將在 第二部分 中看到原因。
一些影像格式可以包含透明度,例如 GIF 和 PNG,但 BMP 和 JPEG 不行。GIF 特別適合圖形表示,而 PNG 適合在簡單背景上疊加物件的圖片。它們都是無損的,但 GIF 圖片只能包含 256 種不同的顏色(在標題中指定),而且儘管壓縮效果很好,但轉換為 PNG 檔案的照片通常會佔用 BMP 檔案的 75%。對於 JPEG,在一個常見問題解答文章中,你可以看到以下對“我可以製作透明的 JPEG 嗎?”這個問題的答案:“不行。JPEG 不支援透明度,並且在短期內也不太可能支援透明度。事實證明,在 JPEG 中新增透明度並非易事;如果你想了解詳細資訊,請繼續閱讀”。然後,我們被告知,在 GIF 圖片中,透明度是透過讓一個未使用的顏色值標記出透明區域來引入的,但這種方法不能用於 JPEG。它可以用於 BMP,其中 16777216 種可能的顏色中很容易遺漏一種來標記透明區域;但不能用於 JPEG,因為 JPEG 中的顏色值是不精確的。透明度將為每個點佔用一位,這個新的分量可以進行與三個 YCbCr 分量相同的處理。然而,這種方法被拒絕的理由是 JPEG 過程不適合處理急劇過渡:如果要令人滿意地再現圍繞孔洞的邊界(透過孔洞可以看到強烈偏離的顏色),那麼透明度分量的餘弦變換數字只能用小的數字進行量化,這樣檔案就會佔用相當大的空間。這是真的,但圖片仍然會比 PNG 格式佔用更小的空間,而且,透明度通常只是暫時使用。很容易對 JPEG 檔案進行排列,使其能夠支援透明度。
然而,由於餘弦變換和透明度分量的量化並沒有帶來多少益處,因此應省略這些操作,並將透明度位的寫入方式如下:我們依次從左到右、從右到左沿水平線移動,使畫素相鄰,在此位序列中,我們將每個不間斷的 0 或 1 區間替換為 0 或 1 的數量(這些數量的總和等於寬度乘以高度)。然後對得到的自然數序列進行編碼,可以在顏色資料之前寫入檔案。透過這種方法,透明區域將與原始影像完全一致。在左側影像中,黑色被設定為透明,影像疊加在藍色背景上,形成了右側影像,儘管此影像質量很低,但透明區域保持不變。
-
原始
-
透明度
在影像中引入透明度的過程可以透過 BMP 格式的影像進行,例如。BMP 格式目前不支援透明度,但我們可以用一張同樣是 BMP 格式的單色影像作為伴隨影像來確定透明區域。單色影像只包含兩種不同的顏色,通常是黑色和白色。兩種顏色的 RGB 值在標頭檔案中宣告(或者更確切地說是標頭檔案用必要的位元組延長來包含此資訊),並且資料 - 每個點的 1 位 - 與普通 BMP 檔案中的 RGB 值以相同的方式寫入:逐行寫入,但將每 8 位塊轉換為一個位元組(並且位元組行的長度能被 4 整除)。這種方法得到了 *Windows* 點陣圖繪製過程的支援:如果我們讓帶顏色的影像中的透明區域為黑色,並讓它在黑白單色影像中為白色區域,那麼 *Windows* 具有直接將兩個檔案的資料傳輸到螢幕的程式,從而生成一個透明區域為空的影像,這樣我們就可以透過它看到底層 - 例如桌面。










