Unraveling the JPEG file
(文章還剩實(shí)踐部分沒(méi)寫(xiě),答辯過(guò)后補(bǔ)上...)
JPEG文件在當(dāng)下數(shù)字化生活中是無(wú)處不在的,但是在熟悉的JPEG面紗背后,隱藏著一些算法,它們?nèi)コ巳祟愌壑袩o(wú)法察覺(jué)到的細(xì)節(jié)。這產(chǎn)生了最高的視覺(jué)質(zhì)量與最小的文件大小。讓我們來(lái)看看這一算法。
引言
我們發(fā)送圖片給朋友的時(shí)候,并不需要擔(dān)心哪個(gè)設(shè)備或者瀏覽器或者操作系統(tǒng)的兼容性,我們只是把圖片"發(fā)出去"。但是就像網(wǎng)絡(luò)傳輸一樣,只是傳輸卻沒(méi)有其他的措施會(huì)造成兼容性極差,所以需要一種協(xié)議或者一種標(biāo)準(zhǔn)。于是一組人在1992年創(chuàng)建了JPEG,一種數(shù)字圖像壓縮的標(biāo)準(zhǔn)。任何曾經(jīng)使用過(guò)互聯(lián)網(wǎng)的人都可能看到過(guò)JPEG編碼的圖像。它是迄今為止最普遍的編碼、發(fā)送和存儲(chǔ)圖像的方式。從網(wǎng)頁(yè)到電子郵件到社交媒體,JPEG每天被使用數(shù)十億次-幾乎每次我們?cè)诰W(wǎng)上查看或發(fā)送圖片。沒(méi)有JPEG,網(wǎng)絡(luò)就會(huì)少一點(diǎn)色彩并且慢很多。
所以這篇文章里將介紹一下關(guān)于如何將存儲(chǔ)在計(jì)算機(jī)上的壓縮數(shù)據(jù)轉(zhuǎn)換為顯示在屏幕上的圖像。當(dāng)然此文首先會(huì)對(duì)該文進(jìn)行部分翻譯、然后結(jié)合MROS大神寫(xiě)的一個(gè)JPEG教程進(jìn)行講解,當(dāng)然其中會(huì)加上自己的理解進(jìn)行整理和驗(yàn)證。如果能夠真正理解圖像的壓縮步驟,感覺(jué)對(duì)之后的圖像處理這一部分的學(xué)習(xí)也是有幫助的。
開(kāi)始
首先雙手奉上女神的照片:
接下來(lái)我們就拿這張圖片作為例子來(lái)講解,如果我們用文字編輯器打開(kāi)圖片就會(huì)發(fā)現(xiàn)是一堆亂碼:
因?yàn)檫@是文字編輯器不能識(shí)別的格式,用文字編輯器打開(kāi)圖片,既讓計(jì)算機(jī)感到疑惑同時(shí)也不能讓我們得到正確的可視結(jié)果。因?yàn)槲覀兊拇蜷_(kāi)方式不正確,我們?nèi)绻斫釰PEG圖像是如何解碼的,我們需要查看原始流,即查看二進(jìn)制數(shù)據(jù)。可以利用專門(mén)查看hex編碼的編輯器來(lái)查看:
我們現(xiàn)在隨意修改其中的一些數(shù)字,可以發(fā)現(xiàn)有些數(shù)字的更改是無(wú)傷大雅的,但是有一些數(shù)字一旦修改可能會(huì)損壞整個(gè)圖像,或者造成圖像顏色和位置發(fā)生變動(dòng)。
很難通過(guò)這樣的方式來(lái)解釋如何從這些字節(jié)中重建圖像,因?yàn)閖peg壓縮實(shí)際上是由三種不同的壓縮技術(shù)組成的,它們被應(yīng)用在連續(xù)的層中。我們將分別查看每一層壓縮,以解開(kāi)我們正在看到的神秘行為。
JPEG壓縮的三層
1.色度次采樣(Chrominance Subsampling)
2.離散余弦變換(Discrete Cosine Transform & Quantization)
3.掃描寬度、霍夫曼編碼(Run-length,Delta&Huffman Encoding)
首先我們需要了解這種壓縮的規(guī)模,請(qǐng)注意上面的圖像是使用確切的79,819個(gè)數(shù)字表示的,大約是79千字節(jié)。如果沒(méi)有壓縮存儲(chǔ),則每個(gè)像素需要三個(gè)數(shù)字-每個(gè)紅色、綠色和藍(lán)色組件都需要一個(gè)數(shù)字。這意味著總共有917,700個(gè)數(shù)字,約917千字節(jié)。使用jpeg壓縮,結(jié)果文件要小十倍以上!而jpeg被稱為有損壓縮技術(shù),圖像由于壓縮而改變并丟失了一些細(xì)節(jié)
Chrominance Subsampling
現(xiàn)在破譯要簡(jiǎn)單一些。這幾乎是一個(gè)簡(jiǎn)單的顏色列表,每個(gè)字節(jié)只改變一個(gè)像素,但它已經(jīng)幾乎是未壓縮圖像的兩倍(對(duì)于這個(gè)較小的大小,大約是300 kb)。可以看出,這些數(shù)字并不代表標(biāo)準(zhǔn)的紅色、綠色和藍(lán)色組件,因?yàn)橛?替換所有數(shù)字會(huì)使圖像變成綠色(而不是黑色)。這是因?yàn)檫@些字節(jié)表示圖像的y(亮度)、cb(相對(duì)藍(lán)度)和cr(相對(duì)紅度)。為什么不直接用RGB呢?畢竟,這就是大多數(shù)現(xiàn)代屏幕的工作原理。您的顯示器可以通過(guò)打開(kāi)每個(gè)像素的不同強(qiáng)度的紅色、綠色和藍(lán)色燈來(lái)顯示任何顏色。白色是通過(guò)打開(kāi)顯示的。
這也和人類眼睛的工作原理非常相似。我們眼中的顏色受體被稱為“錐”,分為三種類型,每種類型對(duì)紅色、綠色或藍(lán)色都很敏感。我們眼中的另一種感受器-棒,只能檢測(cè)到亮度的變化,但它們要敏感得多。我們的眼睛里有大約1.2億根棒狀物。
這意味著我們的眼睛在檢測(cè)亮度變化方面比在檢測(cè)顏色變化方面要好得多。如果我們能把顏色和亮度分開(kāi),我們就可以在沒(méi)有人注意到的情況下去除一點(diǎn)顏色。色度次采樣是以比亮度分量更低的分辨率來(lái)表示圖像的顏色分量的過(guò)程。在上面的例子中,每個(gè)像素都有一個(gè)y分量,而每個(gè)由四個(gè)像素組成的離散組正好有一個(gè)CB和一個(gè)cr分量。因此,圖像中包含的顏色信息只有最初的四分之一。這就是為什么從上面的編輯器中刪除一個(gè)數(shù)字完全破壞了顏色。在這里,組件存儲(chǔ)為y cbcr。刪除第一個(gè)數(shù)字將使CB值被解釋為y,cr被解釋為CB,并創(chuàng)建一個(gè)波動(dòng)效應(yīng),在圖像中翻轉(zhuǎn)所有顏色。
Discrete Cosine Transform & Quantization
這一層壓縮很大程度上是jpeg的定義特性。在將顏色轉(zhuǎn)換為ycbcr之后,組件將被單獨(dú)壓縮,因此我們可以在本文的其余部分只關(guān)注y分量。下面是應(yīng)用這個(gè)層的y組件的字節(jié)。
離散余弦變換是將圖像分解成8x8塊并將每個(gè)塊轉(zhuǎn)換成這64個(gè)系數(shù)的組合的過(guò)程。
如果我們并不是對(duì)8*8像素點(diǎn)而是對(duì)整個(gè)獨(dú)享進(jìn)行離散余弦變換,得到的就為上圖。并且可以不斷刪除結(jié)尾處的數(shù)據(jù),但是一旦變更開(kāi)頭處的數(shù)據(jù),就會(huì)造成肉眼可見(jiàn)的亮度變化。原因是開(kāi)頭處為圖像的低頻變化,結(jié)尾處為高頻變化。
Run-Length, Delta & Huffman Encoding
run-length encoding是用三個(gè)bytes去指定顏色,還有一個(gè)byte去指定有多少個(gè)像素有這個(gè)顏色。
delta-encoding是記錄變化量而不是原值,比如說(shuō)存儲(chǔ)值為12 13 14 13 2,則就可以表示為:12 1 1 -1 -1。每個(gè)DCT塊中的第一個(gè)值稱為dc值,每個(gè)dc值相對(duì)于前面的dc值進(jìn)行增量編碼。因此,改變第一個(gè)塊的亮度將影響圖像中的所有塊。
JPEG解碼流程
正如前面所說(shuō)的一樣,JPEG是一個(gè)標(biāo)準(zhǔn),而不是單單一個(gè)算法。包含了多種壓縮算法以及編碼方式,也就是說(shuō)兩張jpeg圖片之后使用的算法可能完全不同。
如果用壓縮算法進(jìn)行區(qū)分的話,可以分為sequential、progressive、hierarchical和lossless,其中sequential會(huì)從上至下解碼:
progressive則會(huì)在解碼過(guò)程中,從模糊逐步變得清晰:
除了壓縮算法,還有編碼方式不同:霍夫曼編碼、算術(shù)編碼。除了壓縮算法和編碼方式,還有數(shù)據(jù)的粒度,可以理解為精度。先介紹所有JPEG規(guī)范組合中最簡(jiǎn)單的一種:baseline,它使用的壓縮算法為sequential,編碼方式采用的為霍夫曼編碼,精度為8bit。而JPEG的編碼與解碼過(guò)程可以由下圖表示:
其中,DCT變換以及霍夫曼編碼都是完全可逆的運(yùn)算,如果只有這兩個(gè)步驟,呢么得到的圖片就是無(wú)損的。但是為了進(jìn)一步提高壓縮俠侶,baseline方法會(huì)拋棄掉一些"精細(xì)結(jié)構(gòu)",就像語(yǔ)音識(shí)別時(shí)會(huì)去掉音高等精細(xì)結(jié)構(gòu)而只是保存采樣數(shù)據(jù)一樣。而從圖中可以看出將顏色從RGB空間轉(zhuǎn)換成YCbCr空間后降采樣 以及 在DCT變換后的量化數(shù)據(jù)都是去掉這些精細(xì)結(jié)構(gòu)。
一些概念
降采樣
縮小圖像(降采樣)的目的主要有兩個(gè):1.使得圖像符合顯示區(qū)域的大小;2.生成對(duì)應(yīng)圖像的縮略圖。原理是這樣的:對(duì)于一幅圖像尺寸為M*N,對(duì)其進(jìn)行s倍 的下采樣,即得到\((M/s)*(N/s)\) 儲(chǔ)存的分辨率圖像。如果考慮是矩陣形式的圖像,就是把原始圖像 \(s*s\)窗口內(nèi)的圖像變成一個(gè)像素,這個(gè)像素點(diǎn)就是窗口內(nèi)所有像素的均值\(P_k=\frac{\sum X_{i}}{S^{2}}\)
范式霍夫曼編碼
左邊就是霍夫曼樹(shù),讓所有節(jié)點(diǎn)維持高度不變,但盡量往右移動(dòng),得到了右圖。由于兩棵樹(shù)的葉子節(jié)點(diǎn)高度相等,它們的壓縮率是完全相等的。我們用左側(cè)這棵樹(shù)來(lái)記錄編碼信息,需要把整棵樹(shù)的結(jié)構(gòu)都記錄下來(lái);但如果使用的是右側(cè)的樹(shù),只需要記錄在高度h時(shí)有幾個(gè)葉子幾點(diǎn),就能夠完全復(fù)原出右側(cè)的霍夫曼樹(shù),所以范式霍夫曼樹(shù)能夠減少存儲(chǔ)編碼信息的空間用量。這個(gè)特性可以用于加速解碼。
例如用0b0代表A,0b10代表B,0b11代表C,則AABCAAA壓縮為0b001011000.
YCbCr色彩空間
RGB、YUV和YCbCr都是人為規(guī)定的色彩模型或顏色空間(有時(shí)也叫彩色系統(tǒng)或彩色空間)。它的用途是在某些標(biāo)準(zhǔn)下用通常可接受的方式對(duì)彩色加以描述。本質(zhì)上,色彩模型是坐標(biāo)系統(tǒng)和子空間的闡述。
其中RGB是我們常見(jiàn)的紅藍(lán)綠,依據(jù)人眼識(shí)別的顏色定義出的空間。但是RGB的細(xì)節(jié)很難進(jìn)行數(shù)字化的調(diào)整,它將色調(diào)、亮度、飽和度三個(gè)量放在一起表示。是最通用的面向硬件的彩色模型。該模型用于彩色監(jiān)視器和一大類彩色視頻攝像。每個(gè)像素點(diǎn)需要8bits*3 = 24bits
而YUV空間中,每一個(gè)顏色有一個(gè)亮度信號(hào)Y和兩個(gè)色度信號(hào)U和V,亮度信號(hào)時(shí)強(qiáng)度的感覺(jué),和色度信號(hào)斷開(kāi),這樣的話強(qiáng)度就能夠在不影響顏色的情況下改變。YUV使用RGB的信息,如果只有Y信號(hào)分量而沒(méi)有U、V分量,那么這樣表示的圖像就是黑白灰度圖像。彩色電視采用YUV空間正是為了用亮度信號(hào)Y解決彩色電視機(jī)與黑白電視機(jī)的兼容問(wèn)題,使黑白電視機(jī)也能接收彩色電視信號(hào)。
YUV和RGB的轉(zhuǎn)換:Y = 0.299 R + 0.587 G + 0.114 BU = -0.1687 R - 0.3313 G + 0.5 B + 128V = 0.5 R - 0.4187 G - 0.0813 B + 128R = Y + 1.402 (V-128)G= Y - 0.34414 (U-128) - 0.71414 (V-128)B= Y + 1.772 (U-128)YCbCr 其實(shí)是YUV經(jīng)過(guò)縮放和偏移的翻版。其中Y與YUV 中的Y含義一致,Cb,Cr 同樣都指色彩,只是在表示方法上不同而已。YCbCr其中Y是指亮度分量,Cb指藍(lán)色色度分量,而Cr指紅色色度分量。JPEG、MPEG均采用此格式。
YCbCr與RGB的相互轉(zhuǎn)換Y=0.299R+0.587G+0.114BCb=0.564(B-Y)Cr=0.713(R-Y)R=Y+1.402CrG=Y-0.344Cb-0.714CrB=Y+1.772CbYCbCr 有許多取樣格式,主要的采樣格式有YCbCr 4:2:0、YCbCr 4:2:2、YCbCr 4:1:1和 YCbCr 4:4:4。其中YCbCr 4:1:1 比較常用,其含義為:每個(gè)點(diǎn)保存一個(gè) 8bit 的亮度值(也就是Y值),每 2x2 個(gè)點(diǎn)保存一個(gè) Cr 和Cb 值,圖像在肉眼中的感覺(jué)不會(huì)起太大的變化。所以,原來(lái)用 RGB(R,G,B 都是 8bit unsigned) 模型,每個(gè)點(diǎn)需要 8x3=24 bits(如下圖第一個(gè)圖). 而僅需要 8+(8/4)+(8/4)=12bits,平均每個(gè)點(diǎn)占12bits。這樣就把圖像的數(shù)據(jù)壓縮了一半。
再來(lái)具體解釋一下主要的采樣格式:
(1)YUV 4:4:4
YUV三個(gè)信道的抽樣率相同,因此在生成的圖像里,每個(gè)象素的三個(gè)分量信息完整(每個(gè)分量通常8比特),經(jīng)過(guò)8比特量化之后,未經(jīng)壓縮的每個(gè)像素占用3個(gè)字節(jié)。
下面的四個(gè)像素為: [Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
存放的碼流為: Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3
(2)YUV 4:2:2
每個(gè)色差信道的抽樣率是亮度信道的一半,所以水平方向的色度抽樣率只是4:4:4的一半。對(duì)非壓縮的8比特量化的圖像來(lái)說(shuō),每個(gè)由兩個(gè)水平方向相鄰的像素組成的宏像素需要占用4字節(jié)內(nèi)存。
下面的四個(gè)像素為:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
存放的碼流為: Y0 U0 Y1 V1 Y2 U2 Y3 V3
映射出像素點(diǎn)為:[Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]
(3)YUV 4:1:1
4:1:1的色度抽樣,是在水平方向上對(duì)色度進(jìn)行4:1抽樣。對(duì)于低端用戶和消費(fèi)類產(chǎn)品這仍然是可以接受的。對(duì)非壓縮的8比特量化的視頻來(lái)說(shuō),每個(gè)由4個(gè)水平方向相鄰的像素組成的宏像素需要占用6字節(jié)內(nèi)存
下面的四個(gè)像素為:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3]
存放的碼流為: Y0 U0 Y1 Y2 V2 Y3
映射出像素點(diǎn)為:[Y0 U0 V2] [Y1 U0 V2] [Y2 U0 V2] [Y3 U0 V2]
(4)YUV 4:2:0
4:2:0并不意味著只有Y,Cb而沒(méi)有Cr分量。它指得是對(duì)每行掃描線來(lái)說(shuō),只有一種色度分量以2:1的抽樣率存儲(chǔ)。相鄰的掃描行存儲(chǔ)不同的色度分量,也就是說(shuō),如果一行是4:2:0的話,下一行就是4:0:2,再下一行是4:2:0...以此類推。對(duì)每個(gè)色度分量來(lái)說(shuō),水平方向和豎直方向的抽樣率都是2:1,所以可以說(shuō)色度的抽樣率是4:1。對(duì)非壓縮的8比特量化的視頻來(lái)說(shuō),每個(gè)由2x2個(gè)2行2列相鄰的像素組成的宏像素需要占用6字節(jié)內(nèi)存。
下面八個(gè)像素為:[Y0 U0 V0] [Y1 U1 V1] [Y2 U2 V2] [Y3 U3 V3] [Y5 U5 V5] [Y6 U6 V6] [Y7U7 V7] [Y8 U8 V8]
存放的碼流為:Y0 U0 Y1 Y2 U2 Y3
Y5 V5 Y6 Y7 V7 Y8
映射出的像素點(diǎn)為:[Y0 U0 V5] [Y1 U0 V5] [Y2 U2 V7] [Y3 U2 V7] [Y5 U0 V5] [Y6 U0 V5] [Y7U2 V7] [Y8 U2 V7]
讀取區(qū)段
JPEG壓縮文件可能是由以下幾個(gè)區(qū)段組成的:
除此之外,我們需要在JPEG開(kāi)始和結(jié)尾處加上"文件開(kāi)始"和"文件結(jié)束"標(biāo)記,并且采用何種算法會(huì)和降采樣在同一個(gè)區(qū)段;壓縮圖像數(shù)據(jù)會(huì)前準(zhǔn)一個(gè)SOS區(qū)段,告知解碼器接下來(lái)該如何讀取。綜上可以將JPEG壓縮文件表示為:
在一個(gè)JPEG文件中,一定會(huì)出現(xiàn)SOF0、SOF1....SOF16其中一個(gè)區(qū)段,如果出現(xiàn)的是SOF0就說(shuō)明使用的為baseline。DQT和DHT都可能不止一個(gè):
| SOI | 0xFFD8 | NO |
| EOI | 0xFFD9 | NO |
| DQT | 0xFFDB | YES |
| DHT | 0xFFC4 | YES |
| SOF0 | 0xFFC0 | YES |
| SOS | 0xFFDA | YES |
如果圖像信息里包含了0xff怎么辦?所以在規(guī)定壓縮圖像時(shí)會(huì)在0xff后加上一個(gè)0x00的字節(jié),檢測(cè)時(shí)如果遇到0xff00直接跳過(guò)就行了。而又因?yàn)檫@里一個(gè)碼有2個(gè)字節(jié),所以在寫(xiě)程序是可以兩個(gè)字節(jié)兩個(gè)字節(jié)的讀。
而在baseline中,文件開(kāi)頭、文件結(jié)尾、JFIF特有資訊實(shí)際上都已經(jīng)確定了,所以接下來(lái)只需要確定量化表(DQT)、霍夫曼表、壓縮數(shù)據(jù)、SOF0和SOS就行了,一步一步來(lái)。
讀取DQT
一個(gè)DQT里最多可能有4個(gè)量化表,所以量化表的存放在不同程序下可能會(huì)使用不同的方式下面是一個(gè)量化表的內(nèi)容:
| ① | 1 byte | 高 4 bits 表示每個(gè)量化值的大小,0 代表 1 byte,1 代表 2 bytes 低 4 buts 表示本量化表的 id , id 可爲(wèi) 0, 1, 2, 3 |
| ② | 64 或 128 byte | 64 個(gè) 1 或 2 bytes 的量化值,是 1 byte 還是 2 bytes 取決於 ① 的高 4 bits |
讀取霍夫曼編碼表
| ① | 1 byte | 高 4 bits 代表本表是直流還是交流, 0 是直流, 1 是交流 低 4 bits 代表是 0 號(hào)表還是 1 號(hào)表, 0 是 0 號(hào) , 1 是 1 號(hào) |
| ② | 16 bytes | 第 n 個(gè) byte 代表高度爲(wèi) n 時(shí),霍夫曼樹(shù)有幾個(gè)葉子節(jié)點(diǎn) |
| ③ | 葉子節(jié)點(diǎn)數(shù)量bytes | 代表葉子節(jié)點(diǎn)所對(duì)應(yīng)的信源符號(hào),葉子從低到高,從左到右 |
紅色就是直流1號(hào),紫色部分就為形成的范式霍夫曼樹(shù)的葉節(jié)點(diǎn)數(shù)目,葉子節(jié)點(diǎn)應(yīng)該有2+2+5+1+5+1=16,所以綠色部分應(yīng)該有16個(gè)數(shù)值代表葉子節(jié)點(diǎn)上對(duì)應(yīng)的信源符號(hào);如果不足16個(gè)數(shù)值,說(shuō)明這個(gè)DHT區(qū)段可能包含多個(gè)霍夫曼表,在下一個(gè)霍夫曼表中繼續(xù)讀取。
讀取SOF0區(qū)段
SOF0區(qū)段記錄了圖片寬高以及各個(gè)顏色分量的信息,有了這些數(shù)據(jù)我們才能夠讀取SOS段中的壓縮圖像數(shù)據(jù),不過(guò)先看SOF0區(qū)段:
| ① | 1 byte | 精度 | baseline 流程的精度固定爲(wèi) 8 ,也就是說(shuō)用 1 byte 來(lái)存取色彩空間的數(shù)值即可 |
| ② | 2 bytes | 圖片高度 | |
| ③ | 2 bytes | 圖片寬度 | |
| ④ | 1 byte | 有幾個(gè)顏色分量 | JFIF 規(guī)定顏色空間爲(wèi) YCbCr 因此顏色分量數(shù)量固定爲(wèi) 3 |
| ⑤ | 9 bytes | 各個(gè)顏色分量的詳細(xì)資訊 | 見(jiàn)下一張表 |
上表中的5是下表重復(fù)三次,因?yàn)樾枰謩e描述3個(gè)顏色分量的信息:
| ① | 1 byte | 顏色分量 id | 1 表示 Y , 2 表示 Cb , 3 表示 Cr |
| ② | 1 byte | 採(cǎi)樣率 | 高 4 bit 代表水平採(cǎi)樣率 ,低 4 bit 代表垂直採(cǎi)樣率。採(cǎi)樣率可以是 1, 2, 3, 4 |
| ③ | 1 byte | 量化表 id | 最後解碼時(shí),要選擇哪一個(gè)量化表對(duì)該顏色分量進(jìn)行量化 |
讀取SOS區(qū)段
| ① | 1 byte | 有幾個(gè)顏色分量 | |
| ② | 2 * 3 bytes | 顏色分量對(duì)應(yīng)的霍夫曼表 | 每個(gè)顏色分量佔(zhàn)用 2 bytes , 見(jiàn)下一張表 |
| ③ | 3 bytes | baseline 流程用不到 | 在 baseline 流程固定爲(wèi) 0x003F00 |
② 的內(nèi)容爲(wèi)下表重重復(fù)3 次:
| ① | 1 byte | 顏色分量 id | 1 表示 Y,2 表示 Cb,3 表示 Cr |
| ② | 1 byte | 對(duì)應(yīng)的霍夫曼表 id | 高 4 bit 代表直流(DC)霍夫曼表,低 4 bit 代表交流(AC)霍夫曼表 |
讀取壓縮圖像數(shù)據(jù)
數(shù)據(jù)流切割來(lái)看,可以看成一個(gè)接一個(gè)的 MCU 串:
[MCU1], [MCU2], [MCU3], [MCU4], ....
而一個(gè) MCU 又可以進(jìn)一步切割成(假設(shè) Y 水平、垂直採(cǎi)樣率爲(wèi) 2 ,Cb, Cr 水平、垂直採(cǎi)樣率爲(wèi) 1)不同顏色分量的串連,以 Y -> Cb -> Cr 的順序:
[Y1, Y2, Y3, Y4, Cb1, Cr1]
這裏的 Y1, Y2, .... Cr1 ,都是一個(gè) 8 * 8 的 block 了,所以之後我們只要瞭解一個(gè) block 如何讀取,就大功告成了。
讀取一個(gè)block
每個(gè)block都是8*8的,最左上角的數(shù)值就是直流變量,要使用直流霍夫曼表來(lái)解碼,而與下的63個(gè)數(shù)值為交流變量。
JPEG分塊機(jī)制
因?yàn)樵賡equential算法中,是從上至下邊收數(shù)據(jù)邊進(jìn)行解碼的,所以說(shuō)明JPEG文件必然是分塊進(jìn)行壓縮的,因?yàn)椴恍枰浪械臄?shù)據(jù)就已經(jīng)可以開(kāi)始解碼:
MCU是最小編碼單元Minimum Coded Unit的縮寫(xiě)(通信協(xié)議上某一層上所能通過(guò)的最大數(shù)據(jù)包大小的概念為MTU)。MCU的寬高并不固定為16px也不一定是正方形,而是取決于顏色分量的采樣率。
JPEG使用的為YCbCr色彩空間,采樣圖如上。每個(gè)顏色分量的最基本單元是block,一個(gè)block的寬、高固定為8*8:
MCU的寬 = 8 * 最高水平采樣率 MCU的高 = 8 * 最高垂直采樣率Cb、Cr的最左上角對(duì)應(yīng)到了MCU的左上4個(gè)px:
MCU從左到右、再?gòu)纳系较?#xff1a;
一個(gè)顏色分量?jī)?nèi)部各個(gè)block的順序一樣是從左到右、從上到下:
MCU、顏色分量、block關(guān)系
讀取圖像壓縮數(shù)據(jù)時(shí),需要先讀取MCU信息,在讀取MCU時(shí)又需要讀取block的信息。
解碼 decode!
由于已經(jīng)將JPEG文件的所有區(qū)段全部讀取出來(lái)了,接下來(lái)就是簡(jiǎn)單的轉(zhuǎn)換,就能夠還原為原始圖像數(shù)據(jù),接下來(lái)將按照步驟來(lái)依次轉(zhuǎn)換。
反量化
從DQT區(qū)段中已經(jīng)讀出了量化表,在SOF0區(qū)段中也知道了各個(gè)顏色分量所對(duì)應(yīng)的量化表id,一個(gè)block和一個(gè)量化表都是8*8,將它們對(duì)應(yīng)的位置相乘就完成這個(gè)轉(zhuǎn)換了。
反zigzag
zigzag時(shí),會(huì)將一個(gè)block以下圖的順序重新排列:
反zigzag就是要將這個(gè)過(guò)程逆轉(zhuǎn)過(guò)來(lái)進(jìn)行還原
反向DCT變換
升采樣與YCbCr轉(zhuǎn)RGB顏色空間
照著公式來(lái)變換即可。
最后將圖像的各個(gè)MCU拼接起來(lái)就可以得到原圖了。
一個(gè)實(shí)例
下面給出一個(gè)將JPEG文件轉(zhuǎn)換成bmp文件的程序:https://github.com/MROS/jpeg_decoder/blob/master/main.cpp
轉(zhuǎn)載于:https://www.cnblogs.com/yunlambert/p/10969811.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Unraveling the JPEG file的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 学习OpenCV(2)OpenCV初探-
- 下一篇: 电信企业文化