JPEG的文件格式

JPEG的文件格式

JPEG文件大體上可以分成以下兩個部分:標記碼(Tag)加壓縮數據。先介紹標記碼部分。

標記碼部分給出了JPEG圖象的所有信息(有點類似於BMP中的頭信息,但要複雜的多),如圖象的寬、高、Huffman表、量化表等等。標記碼有很多,但絕大多數的JPEG文件只包含幾種。標記碼的結構爲:

SOI

DQT

             DRI

                    SOF0

                           DHT

                                  SOS

                                  …

                                  EOI

標記碼由兩個字節組成,高字節爲0XFF,每個標記碼之前可以填上個數不限的填充字節0XFF。

下面介紹一些常用的標記碼的結構及其含義。

(1)SOI(Start of Image)

標記結構      字節數

0XFF             1

0XD8             1

可作爲JPEG格式的判據(JFIF還需要APP0的配合)

(2)APP0(Application)

標記結構       字節數    意義

0XFF             1

0XE0             1

Lp                 2            APP0標記碼長度,不包括前兩個字節0XFF,0XE0

Identifier 5            JFIF識別碼 0X4A,0X46,0X49,0X46,0X00

Version           2            JFIF版本號 可爲0X0101或者0X0102

Units              1            單位,等於零時表示未指定,爲1表示英寸,爲2表示

釐米

Xdensity  2            水平分辨率

Ydensity  2            垂直分辨率

Xthumbnail     1            水平點數

Ythumbnail     1            垂直點數

RGB0             3            RGB的值

RGB1             3            RGB的值

RGBn             3            RGB的值,n=Xthumbnail*Ythumbnail

APP0是JPEG保留給Application所使用的標記碼,而JFIF將文件的相關信息定義在此標記中。

(3)DQT(Define Quantization Table)

標記結構       字節數    意義

0XFF             1

0XDB            1

Lq                 2            DQT標記碼長度,不包括前兩個字節0XFF,0XDB

(Pq,Tq)          1            高四位Pq爲量化表的數據精確度,Pq=0時,Q0~Qn的

值爲8位,Pq=1時,Qt的值爲16位,Tq表示量化表的

編號,爲0~3。在基本系統中,Pq=0,Tq=0~1,也就是

說最多有兩個量化表。

Q0                 1或2      量化表的值,Pq=0時;爲一個字節,Pq=1時,爲兩個

字節

Q1                 1或2      量化表的值,Pq=0時;爲一個字節,Pq=1時,爲兩個

字節

Qn                 1或2      量化表的值,Pq=0時,爲一個字節;Pq=1時,爲兩個

字節。n的值爲0~63,表示量化表中64個值(之字形排

列)

(4)DRI(Define Restart Interval)

此標記需要用到最小編碼單元(MCU,Minimum Coding Unit)的概念。前面提到,Y分量數據重要,UV分量的數據相對不重要,所以可以只取UV的一部分,以增加壓縮比。目前支持JPEG格式的軟件通常提供兩種取樣方式YUV411和YUV422,其含義是YUV三個分量的數據取樣比例。舉例來說,如果Y取四個數據單元,即水平取樣因子Hy乘以垂直取樣因子Vy的值爲4,而U和V各取一個數據單元,即Hu×Vu=1,Hv×Vv=1。那麼這種部分取樣就稱爲YUV411。如圖9.7所示:

圖9.7     YUV411的示意圖

圖9.8     YUV111的排列順序

易知YUV411有50%的壓縮比(原來有12個數據單元,現在有6個數據單元),YUV422有33%的壓縮比(原來有12個數據單元,現在有8個數據單元)。

那麼你可能會想,YUV911,YUV1611壓縮比不是更高嘛?但是要考慮到圖象質量的因素。所以JPEG標準規定了最小編碼單元MCU,要求Hy×Vy+Hu×Vu+Hv×Vv≤10。

MCU中塊的排列方式與H,V的值有密切關係,如圖9.8、圖9.9、圖9.10所示。

圖9.9     YUV211的排列順序

圖9.10   YUV411的排列順序

標記結構       字節數    意義

0XFF             1

0XDD            1

Lr                  2            DRI標記碼長度,不包括前兩個字節0XFF,0XDD

Ri                 2            重入間隔的MCU個數,Ri必須是一MCU行中MCU

個數的整數,最後一個零頭不一定剛好是Ri個MCU。

每個重入間隔各自獨立編碼。

(5)SOF(Start of Frame) 在基本系統中,只處理SOF0

標記結構       字節數    意義

0XFF             1

0XC0             1

Lf                  2            SOF標記碼長度,不包括前兩個字節0XFF,0XC0

P                   1            基本系統中,爲0X08

Y                   2            圖象高度

X                   2            圖象寬度

Nf                 1            Frame中的成分個數,一般爲1或3,1代表灰度圖,3

代表真彩圖

C1                 1            成分編號1

(H1,V1)   1            第一個水平和垂直採樣因子

Tq1        1            該量化表編號

C2                 1            成分編號2

(H2,V2)   1            第二個水平和垂直採樣因子

Tq2        1            該量化表編號

Cn                 1            成分編號n

(Hn,Vn)   1            第n個水平和垂直採樣因子

Tqn        1            該量化表編號

(6)DHT(Define Huffman Table)

標記結構       字節數    意義

0XFF             1

0XC4             1

Lh                 2            DHT標記碼長度,不包括前兩個字節0XFF,0XC4

(Tc,Th)          1           

L1                 1

L2                 1

…                 

L16         1

V1                 1

V2                 1

Vt                  1

Tc爲高4位,Th爲低4位。在基本系統中,Tc爲0或1,爲0時,指DC所用的Huffman表,爲1時,指AC所用的Huffman表。Th表示Huffman表的編號,在基本系統中,其值爲0或1。所以,在基本系統中,最多有4個Huffman表,如下所示:

Tc   Th   Huffman表編號(2×Tc+Th)

0     0

1     1

0     2

1     1     3

Ln表示每個n比特的Huffman碼字的個數,n=1~16

Vt表示每個Huffman碼字所對應的值,也就是我們前面所講的符號1,對DC來說該值爲(Size),對AC來說該值爲(RunLength,Size)。

t=L1+L2+…L16

(7)SOS(Start of Scan)

標記結構       字節數    意義

0XFF             1

0XDA            1

Ls                  2            DHT標記碼長度,不包括前兩個字節0XFF,0XDA

Ns                 1

Cs1         1

(Td1,Ta1)       1

Cs2         1

(Td2,Ta2)       1

CsNs             1

(TdNs,TaNs)  1

Ss                  1

Se                  1

(Ah,Al) 1

Ns爲Scan中成分的個數,在基本系統中,Ns=Nf(Frame中成分個數)。CSNs爲在Scan中成分的編號。TdNs爲高4位,TaNs爲低4位,分別表示DC和AC編碼表的編號。在基本系統中Ss=0,Se=63,Ah=0,Al=0。

(8)EOI(End of Image)   結束標誌

標記結構       字節數    意義

0XFF             1

0XD9             1




Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=677394

 

+++++++++++++++++++++++++++++++++++++++++++++++++

1 簡介

微處理機中的存放順序有正序(big endian)和逆序(little endian)之分。正序存放就是高字節存放在前低字節在後,而逆序存放就是低字節在前高字節在後。例如,十六進制數爲A02B,正序存放就是A02B,逆序存放就是2BA0。摩托羅拉(Motorola)公司的微處理器使用正序存放,而英特爾(Intel)公司的微處理器使用逆序。JPEG文件中的字節是按照正序排列的。

 


JPEG委員會在制定JPEG標準時,定義了許多標記(marker)用來區分和識別圖像數據及其相關信息,但筆者沒有找到JPEG委員會對JPEG文件交換格式的明確定義。直到1998年12月從分析網上具體的JPG圖像來看,使用比較廣泛的還是JPEG文件交換格式(JPEG File Interchange Format,JFIF)本號爲1.02。這是1992年9月由在C-Cube Microsystems公司工作的Eric Hamilton提出的。此外還有TIFF JPEG等格式,但由於這種格式比較複雜,因此大多數應用程序都支持JFIF文件交換格式。

 

JPEG文件使用的顏色空間是CCIR 601推薦標準進行的彩色空間(參看第7章)。在這個彩色空間中,每個分量、每個像素的電平規定爲255級,用8位代碼表示。從RGB轉換成YCbCr空間時,使用下面的精確的轉換關係:

       Y = 256 * E'y

      Cb = 256 * [E'Cb] + 128

      Cr = 256 * [E'Cr] + 128
其中亮度電平E'y和色差電平E'Cb和E'Cb分別是CCIR 601定義的參數。由於E'y的範圍是0~1,E'Cb和E'Cb的範圍是-0.5~+0.5,因此Y, Cb和Cr的最大值必須要箝到255。於是RGB和YCbCr之間的轉換關係需要按照下面的方法計算。

(1) 從RGB轉換成YCbCr

YCbCr(256級)分量可直接從用8位表示的RGB分量計算得到:

       Y =   0.299 R + 0.587 G  + 0.114 B

     Cb = - 0.1687R - 0.3313G  + 0.5   B + 128

    Cr = 0.5 R - 0.4187G - 0.0813 B + 128

需要注意的是不是所有圖像文件格式都按照R0,G0,B0,…… Rn,Gn,Bn的次序存儲樣本數據,因此在RGB文件轉換成JFIF文件時需要首先驗證RGB的次序。

(2) 從YCbCr轉換成RGB

RGB分量可直接從YCbCr(256級)分量計算得到:

     R = Y                 + 1.402 (Cr-128)

      G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)

      B = Y + 1.772 (Cb-128)

在JFIF文件格式中,圖像樣本的存放順序是從左到右和從上到下。這就是說JFIF文件中的第一個圖像樣本是圖像左上角的樣本。

 

2 文件結構

JFIF文件格式直接使用JPEG標準爲應用程序定義的許多標記,因此JFIF格式成了事實上JPEG文件交換格式標準。JPEG的每個標記都是由2個字節組成,其前一個字節是固定值0xFF。每個標記之前還可以添加數目不限的0xFF填充字節(fill byte)。下面是其中的8個標記:

1.   SOI  0xD8            圖像開始

2.   APP0 0xE0            JFIF應用數據塊

3.   APPn 0xE1 - 0xEF    其他的應用數據塊(n, 1~15)

4.   DQT  0xDB           量化表

5.   SOF0 0xC0            幀開始

6.   DHT  0xC4           霍夫曼(Huffman)表

7.   SOS  0xDA           掃描線開始

8.   EOI  0xD9            圖像結束

爲使讀者對JPEG定義的標記一目瞭然,現將JPEG的標記碼列於表6-05,並保留英文解釋。

表6-05 JPEG定義的標記

 

Symbol

(符號)

Code Assignment

(標記代碼)

Description

(說明)

Start Of Frame markers, non-hierarchical Huffman coding

SOF0

0xFFC0

Baseline DCT

SOF1

0xFFC1

Extended sequential DCT

SOF2

0xFFC2

Progressive DCT

SOF3

0xFFC3

Spatial (sequential) lossless

Start Of Frame markers, hierarchical Huffman coding

SOF5

0xFFC5

Differential sequential DCT

SOF6

0xFFC6

Differential progressive DCT

SOF7

0xFFC7

Differential spatial lossless

Start Of Frame markers, non-hierarchical arithmetic coding

JPG

0xFFC8

Reserved for JPEG extensions

SOF9

0xFFC9

Extended sequential DCT

SOF10

0xFFCA

Progressive DCT

SOF11

0xFFCB

Spatial (sequential) Lossless

Start Of Frame markers, hierarchical arithmetic coding

SOF13

0xFFCD

Differential sequential DCT

SOF14

0xFFCE

Differential progressive DCT

SOF15

0xFFCF

Differential spatial Lossless

Huffman table specification

DHT

0xFFC4

Define Huffman table(s)

arithmetic coding conditioning specification

DAC

0xFFCC

Define arithmetic conditioning table

Restart interval termination

RSTm

0xFFD0~0xFFD7

Restart with modulo 8 counter m

Other marker

SOI

0xFFD8

Start of image

EOI

0xFFD9

End of image

SOS

0xFFDA

Start of scan

DQT

0xFFDB

Define quantization table(s)

DNL

0xFFDC

Define number of lines

DRI

0xFFDD

Define restart interval

DHP

0xFFDE

Define hierarchical progression

EXP

0xFFDF

Expand reference image(s)

APPn

0xFFE0~0xFFEF

Reserved for application use

JPGn

0xFFF0~0xFFFD

Reserved for JPEG extension

COM

0xFFFE

Comment

Reserved markers

TEM

0xFF01

For temporary use in arithmetic coding

RES

0xFF02~0xFFBF

Reserved

 

JPEG文件由下面的8個部分組成:

(1) 圖像開始SOI(Start of Image)標記

(2) APP0標記(Marker)

① APP0長度(length)

② 標識符(identifier)

③ 版本號(version)

④ X和Y的密度單位(units=0:無單位;units=1:點數/英寸;units=2:點數/釐米)

⑤ X方向像素密度(X density)

⑥ Y方向像素密度(Y density)

⑦ 縮略圖水平像素數目(thumbnail horizontal pixels)

⑧ 縮略圖垂直像素數目(thumbnail vertical pixels)

⑨ 縮略圖RGB位圖(thumbnail RGB bitmap)

(3) APPn標記(Markers),其中n=1~15(任選)

① APPn長度(length)

② 由於詳細信息(application specific information)

(4) 一個或者多個量化表DQT(difine quantization table)

① 量化表長度(quantization table length)

② 量化表數目(quantization table number)

③ 量化表(quantization table)

(5) 幀圖像開始SOF0(Start of Frame)

① 幀開始長度(start of frame length)

② 精度(precision),每個顏色分量每個像素的位數(bits per pixel per color component)

③ 圖像高度(image height)

④ 圖像寬度(image width)

⑤ 顏色分量數(number of color components)

⑥ 對每個顏色分量(for each component)

o        ID

o        垂直方向的樣本因子(vertical sample factor)

o        水平方向的樣本因子(horizontal sample factor)

o        量化表號(quantization table#)

(6) 一個或者多個霍夫曼表DHT(Difine Huffman Table)

① 霍夫曼表的長度(Huffman table length)

② 類型、AC或者DC(Type, AC or DC)

③ 索引(Index)

④ 位表(bits table)

⑤ 值表(value table)

(7) 掃描開始SOS(Start of Scan)

① 掃描開始長度(start of scan length)

② 顏色分量數(number of color components)

③ 每個顏色分量

o        ID

o        交流係數表號(AC table #)

o        直流係數表號(DC table #)

④ 壓縮圖像數據(compressed image data)

(8) 圖像結束EOI(End of Image)

表6-06表示了APP0域的詳細結構。有興趣的讀者可通過UltraEdit或者PC TOOLS等工具軟件打開一個JPG圖像文件,對APP0的結構進行分析和驗證。

表6-06 JFIF格式中APP0域的詳細結構

 

偏移

長度

內容

塊的名稱

說明

0

2 byte

0xFFD8

(Start of Image,SOI)

圖像開始

2

2 byte

0xFFE0

APP0(JFIF application segment)

JFIF應用數據塊

4

2 bytes

 

length of APP0 block

APP0塊的長度

6

5 bytes

 

"JFIF"+"0"

識別APP0標記

11

1 byte

 

<Major version>

主要版本號(如版本1.02中的1)

12

1 byte

 

<Minor version>

次要版本號(如版本1.02中的02)

13

1 byte

 

<Units for the X
and Y densities>

X和Y的密度單位

units=0:無單位

units=1:點數/英寸

units=2:點數/釐米

14

2 bytes

 

<Xdensity>

水平方向像素密度

16

2 bytes

 

<Ydensity>

垂直方向像素密度

18

1 byte

 

<Xthumbnail>

縮略圖水平像素數目

19

1 byte

 

<Ythumbnail>

縮略圖垂直像素數目

 

3n

 

< Thumbnail RGB bitmap>

縮略RGB位圖(n爲縮略圖的像素數)

 

 

 

Optional JFIF extension APP0 marker segment(s)

任選的JFIF擴展APP0標記段

 

……

 

……

 

 

2 byte

0xFFD9

(EOI) end-of-file

圖像文件結束標記




Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=675344

 


JPEG 壓縮簡介
-------------

1. 色彩模型

JPEG 的圖片使用的是 YCrCb 顏色模型, 而不是計算機上最常用的 RGB. 關於色
彩模型, 這裏不多闡述. 只是說明, YCrCb 模型更適合圖形壓縮. 因爲人眼對圖片上
的亮度 Y 的變化遠比色度 C 的變化敏感. 我們完全可以每個點保存一個 8bit 的亮
度值, 每 2x2 個點保存一個 Cr Cb 值, 而圖象在肉眼中的感覺不會起太大的變化.
所以, 原來用 RGB 模型, 4 個點需要 4x3=12 字節. 而現在僅需要 4+2=6 字節; 平
均每個點佔 12bit. 當然 JPEG 格式裏允許每個點的 C 值都記錄下來; 不過 MPEG 裏
都是按 12bit 一個點來存放的, 我們簡寫爲 YUV12.

[R G B] -> [Y Cb Cr] 轉換
-------------------------

(R,G,B 都是 8bit unsigned)

| Y | | 0.299 0.587 0.114 | | R | | 0 |
| Cb | = |- 0.1687 - 0.3313 0.5 | * | G | + |128|
| Cr | | 0.5 - 0.4187 - 0.0813| | B | |128|

Y = 0.299*R + 0.587*G + 0.114*B (亮度)
Cb = - 0.1687*R - 0.3313*G + 0.5 *B + 128
Cr = 0.5 *R - 0.4187*G - 0.0813*B + 128

[Y,Cb,Cr] -> [R,G,B] 轉換
-------------------------

R = Y + 1.402 *(Cr-128)
G = Y - 0.34414*(Cb-128) - 0.71414*(Cr-128)
B = Y + 1.772 *(Cb-128)

一般, C 值 (包括 Cb Cr) 應該是一個有符號的數字, 但這裏被處理過了, 方法
是加上了 128. JPEG 裏的數據都是無符號 8bit 的.

2. DCT (離散餘弦變換)

JPEG 裏, 要對數據壓縮, 先要做一次 DCT 變換. DCT 變換的原理, 涉及到數學
知識, 這裏我們不必深究. 反正和傅立葉變換(學過高數的都知道) 是差不多了. 經過
這個變換, 就把圖片裏點和點間的規律呈現出來了, 更方便壓縮.JPEG 裏是對每 8x8
個點爲一個單位處理的. 所以如果原始圖片的長寬不是 8 的倍數, 都需要先補成 8
的倍數, 好一塊塊的處理. 另外, 記得剛纔我說的 Cr Cb 都是 2x2 記錄一次嗎? 所
以大多數情況, 是要補成 16x16 的整數塊.按從左到右, 從上到下的次序排列 (和我
們寫字的次序一樣). JPEG 裏是對 Y Cr Cb 分別做 DCT 變換的.

JPEG 編碼時使用的是 Forward DCT (FDCT) 解碼時使用的 Inverse DCT (IDCT)
下面給出公式:

FDCT:
c(u,v) 7 7 2*x+1 2*y+1
F(u,v) = --------- * sum sum f(x,y) * cos (------- *u*PI)* cos (------ *v*PI)
4 x=0 y=0 16 16

u,v = 0,1,...,7

{ 1/2 當 u=v=0 時
c(u,v) = {
{ 1 其他情況


IDCT:
1 7 7 2*x+1 2*y+1
f(x,y) = --- * sum sum c(u,v)*F(u,v)*cos (------- *u*PI)* cos (------ *v*PI)
4 u=0 v=0 16 16

x,y=0,1...7

這個步驟很花時間, 另外有種 AA&N 優化算法, 大家可以去 inet 自己找一下.
在 Intel 主頁上可以找到 AA&N IDCT 的 MMX 優化代碼.

3. 重排列 DCT 結果
DCT 將一個 8x8 的數組變換成另一個 8x8 的數組. 但是內存裏所有數據都是線
形存放的, 如果我們一行行的存放這 64 個數字, 每行的結尾的點和下行開始的點就
沒有什麼關係, 所以 JPEG 規定按如下次序整理 64 個數字.

 0, 1, 5, 6,14,15,27,28,
 2, 4, 7,13,16,26,29,42,
 3, 8,12,17,25,30,41,43,
 9,11,18,24,31,40,44,53,
10,19,23,32,39,45,52,54,
20,22,33,38,46,51,55,60,
21,34,37,47,50,56,59,61,
35,36,48,49,57,58,62,63

這樣數列裏的相鄰點在圖片上也是相鄰的了.

4. 量化
對於前面得到的 64 個空間頻率振幅值, 我們將對它們作幅度分層量化操作.方
法就是分別除以量化表裏對應值並四捨五入.

for (i = 0 ; i<=63; i++ )
    vector[i] = (int) (vector[i] / quantization_table[i] + 0.5)

下面有張 JPEG 標準量化表. (按上面同樣的彎曲次序排列)

16 11 10 16  24  40  51 61
12 12 14 19  26  58  60 55
14 13 16 24  40  57  69 56
14 17 22 29  51  87  80 62
18 22 37 56  68 109 103 77
24 35 55 64  81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99

這張表依據心理視覺閥製作, 對 8bit 的亮度和色度的圖象的處理效果不錯.
當然我們可以使用任意的量化表. 量化表是定義在 jpeg 的 DQT 標記後. 一般
爲 Y 值定義一個, 爲 C 值定義一個.
量化表是控制 JPEG 壓縮比的關鍵. 這個步驟除掉了一些高頻量, 損失了很高
細節. 但事實上人眼對高空間頻率遠沒有低頻敏感.所以處理後的視覺損失很小.
另一個重要原因是所有的圖片的點與點之間會有一個色彩過渡的過程. 大量的圖象
信息被包含在低空間頻率中. 經過量化處理後, 在高空間頻率段, 將出現大量連續
的零.

5. 0 RLC 編碼
現在我們矢量中有許多連續的 0. 我們可以使用 RLC 來壓縮掉這些 0. 這裏我們
將跳過第一個矢量 (後面將解釋爲什麼) 因爲它的編碼比較特別. 假設有一組矢量
(64 個的後 63 個) 是
57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0, 0 , 0 ,0 , 0,..,0
經過 RLC 壓縮後就是
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB
EOB 是一個結束標記, 表示後面都是 0 了. 實際上, 我們用 (0,0) 表示 EOB
但是, 如果這組數字不以 0 結束, 那麼就不需要 EOB.
由於後面 huffman 編碼的要求, 每組數字前一個表示 0 的數量的必須是 4 bit,
就是說, 只能是 0~15, 所以我們實際這樣編碼:
(0,57) ; (15,0) (2,3) ; (4,2) ; (15,0) (15,0) (1,895) , (0,0)
注意 (15,0) 表示了 16 個連續的 0.

6. huffman 編碼
爲了提高儲存效率, JPEG 裏並不直接保存數值, 而是將數值按位數分成 16 組:

數值 組 實際保存值
0 0 -
-1,1 1 0,1
-3,-2,2,3 2 00,01,10,11
-7,-6,-5,-4,4,5,6,7 3 000,001,010,011,100,101,110,111
-15,..,-8,8,..,15 4 0000,..,0111,1000,..,1111
-31,..,-16,16,..,31 5 00000,..,01111,10000,..,11111
-63,..,-32,32,..,63 6 .
-127,..,-64,64,..,127 7 .
-255,..,-128,128,..,255 8 .
-511,..,-256,256,..,511 9 .
-1023,..,-512,512,..,1023 10 .
-2047,..,-1024,1024,..,2047 11 .
-4095,..,-2048,2048,..,4095 12 .
-8191,..,-4096,4096,..,8191 13 .
-16383,..,-8192,8192,..,16383 14 .
-32767,..,-16384,16384,..,32767 15 .

還是來看前面的例子:
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)
只處理每對數右邊的那個:
57 是第 6 組的, 實際保存值爲 111001 , 所以被編碼爲 (6,111001)
45 , 同樣的操作, 編碼爲 (6,101101)
23 -> (5,10111)
-30 -> (5,00001)
-8 -> (4,0111)
1 -> (1,1)

前面的那串數字就變成了:
(0,6), 111001 ; (0,6), 101101 ; (4,5), 10111; (1,5), 00001; (0,4) , 0111 ;
(2,1), 1 ; (0,0)

括號裏的數值正好合成一個字節. 後面被編碼的數字表示範圍是 -32767..32767.
合成的字節裏, 高 4 位是前續 0 的個數, 低 4 位描述了後面數字的位數.

繼續剛纔的例子, 如果 06 的 huffman 編碼爲 111000
69 = (4,5) --- 1111111110011001
21 = (1,5) --- 11111110110
4 = (0,4) --- 1011
33 = (2,1) --- 11011
0 = EOB = (0,0) --- 1010

那麼最後對於前面的例子表示的 63 個係數 (記得我們將第一個跳過了嗎?) 按位流
寫入 JPG 文件中就是這樣的:
111000 111001 111000 101101 1111111110011001 10111 11111110110 00001
1011 0111 11011 1 1010

DC 的編碼
---------
記得剛纔我們跳過了每組 64 個數據的第一個吧, DC 就是指的這個數字 (後面 63
個簡稱 AC) 代入前面的 FDCT 公式可以得到
c(0,0) 7 7
DC = F(0,0) = --------- * sum sum f(x,y) * cos 0 * cos 0 其中 c(0,0) = 1/2
4 x=0 y=0

1 7 7
= --- * sum sum f(x,y)
8 x=0 y=0

即一塊圖象樣本的平均值. 就是說, 它包含了原始 8x8 圖象塊裏的很多能量. (通常
會得到一個很大的數值)

JPEG 的作者指出連續塊的 DC 率之間有很緊密的聯繫, 因此他們決定對 8x8 塊的
DC 值的差別進行編碼. (Y, Cb, Cr 分別有自己的 DC)

Diff = DC(i) - DC(i-1)

所以這一塊的 DC(i) 就是: DC(i) = DC(i-1) + Diff

JPG 從 0 開始對 DC 編碼, 所以 DC(0)=0. 然後再將當前 Diff 值加在上一個值上得
到當前值.

下面再來看看上面那個例子: (記住我們保存的 DC 是和上一塊 DC 的差值 Diff)

例如上面例子中, Diff 是 -511, 就編碼成

(9, 000000000)

如果 9 的 Huffman 編碼是 1111110 (在 JPG 文件中, 一般有兩個 Huffman 表, 一
個是 DC 用, 一個是 AC 用) 那麼在 JPG 文件中, DC 的 2 進製表示爲

1111110 000000000

它將放在 63 個 AC 的前面, 上面上個例子的最終 BIT 流如下:

1111110 000000000 111000 111001 111000 101101 1111111110011001 10111
11111110110 00001 1011 0111 11011 1 1010

下面簡單敘述一下針對一個數據單元的圖片 Y 的解碼
-----------------------------------------------

在整個圖片解碼的開始, 你需要先初始化 DC 值爲 0.

1) 先解碼 DC:
a) 取得一個 Huffman 碼 (使用 Huffman DC 表)
b) Huffman解碼, 看看後面的數據位數 N
c) 取得 N 位, 計算 Diff 值
d) DC + = Diff
e) 寫入 DC 值: " vector[0]=DC "

2) 解碼 63 個 AC:

------- 循環處理每個 AC 直到 EOB 或者處理到 64 個 AC

a) 取得一個 Huffman 碼 (使用 Huffman AC 表)
b) Huffman 解碼, 得到 (前面 0 數量, 組號)
[記住: 如果是(0,0) 就是 EOB 了]

c) 取得 N 位(組號) 計算 AC
d) 寫入相應數量的 0
e) 接下來寫入 AC
-----------------

下一步的解碼
------------
上一步我們得到了 64 個矢量. 下面我們還需要做一些解碼工作:

1) 反量化 64 個矢量 : "for (i=0;i<=63;i++) vector[i]*=quant[i]"
2) 重排列 64 個矢量到 8x8 的塊中
3) 對 8x8 的塊作 IDCT

對 8x8 塊的 (Y,Cb,Cr) 重複上面的操作 [Huffman 解碼, 步驟 1), 2), 3)]

4) 將所有的有符號的 8bit 數加上 128
5) 轉換 YCbCr 到 RGB

JPG 文件(Byte 級)裏怎樣組織圖片信息
-----------------------------------
注意 JPEG/JFIF 文件格式使用 Motorola 格式, 而不是 Intel 格式, 就是說, 如果
是一個字的話, 高字節在前, 低字節在後.

JPG 文件是由一個個段 (segments) 構成的. 每個段長度 <=65535. 每個段從一個標
記字開始. 標記字都是 0xff 打頭的, 以非 0 字節和 0xFF 結束. 例如 'FFDA' ,
'FFC4', 'FFC0'. 每個標記有它特定意義, 這是由第2字節指明的. 例如, SOS (Start
Of Scan = 'FFDA') 指明瞭你應該開始解碼. 另一個標記 DQT (Define Quantization
Table = 0xFFDB) 就是說它後面有 64 字節的 quantization 表

在處理 JPG 文件時, 如果你碰到一個 0xFF, 而它後面的字節不是 0, 並且這個字節
沒有意義. 那麼你遇到的 0xFF 字節必須被忽略. (一些 JPG 裏, 常用用 0xFF 做某
些填充用途) 如果你在做 huffman 編碼時碰巧產生了一個 0xFF, 那麼就用 0xFF
0x00 代替. 就是說在 jpeg 圖形解碼時碰到 FF00 就把它當作 FF 處理.

另外在 huffman 編碼區域結束時, 碰到幾個 bit 沒有用的時候, 應該用 1 去填充.
然後後面跟 FF.

下面是幾個重要的標記
--------------------

SOI = Start Of Image = 'FFD8'
這個標記只在文件開始出現一次
EOI = End Of Image = 'FFD9'
JPG 文件都以 FFD9 結束

RSTi = FFDi ( i = 0..7) [ RST0 = FFD0, RST7=FFD7]
= 復位標記
通常穿插在數據流裏, 我想是擔心 JPG 解碼出問題吧(應該配合 DRI 使用). 不過很
多 JPG 都不使用它

(SOS --- RST0 --- RST1 -- RST2 --...
...-- RST6 --- RST7 -- RST0 --...)

----
標記
----
下面是必須處理的標記

SOF0 = Start Of Frame 0 = FFC0
SOS = Start Of Scan = FFDA
APP0 = it's the marker used to identify a JPG file which uses the JFIF
specification = FFE0
COM = Comment = FFFE
DNL = Define Number of Lines = FFDC
DRI = Define Restart Interval = FFDD
DQT = Define Quantization Table = FFDB
DHT = Define Huffman Table = FFC4

JPG 文件中 Haffman 表的儲存
---------------------------
JPEG 裏定義了一張表來描述 Haffman 樹. 定義在 DHT 標記後面. 注意: Haffman
代碼的長度限制在 16bit 內.

一般一個 JPG 文件裏會有 2 類 Haffman 表: 一個用於 DC 一個用於 AC (實際有 4
個表, 亮度的 DC,AC 兩個, 色度的 DC,AC 兩個)

這張表是這樣保存的:
1) 16 字節:
第 i 字節表示了 i 位長的 Huffman 代碼的個數 (i= 1 到 16)

2) 這表的長度 (字節數) = 這 16 個數字之和
現在你可以想象這張表怎麼存放的吧? 對應字節就是對應 Haffman 代碼等價數字. 我
不多解釋, 這需要你先了解 Haffman 算法. 這裏只舉一個例子:

Haffman 表的表頭是 0,2,3,1,1,1,0,1,0,0,0,0,0,0,0,0
就是說長度爲 1 的代碼沒有
長度爲 2 的代碼爲 00
01
長度爲 3 的代碼是 100
101
110
長度爲 4 的代碼是 1110
長度爲 5 的代碼是 11110
長度爲 6 的代碼是 111110
長度爲 7 的代碼沒有 (如果有一個的話應該是 1111110)
長度爲 8 的代碼是 11111100
.....
後面都沒有了.

如果表下面的數據是
45 57 29 17 23 25 34 28

就是說
45 = 00
57 = 01
29 = 100
17 = 101
23 = 110
等等...

如果你懂 Haffman 編碼, 這些不難理解

採樣係數
--------
下面講解的都是真彩 JPG 的解碼, 灰度 JPG 的解碼很簡單, 因爲圖形中只有亮度信
息. 而彩色圖形由 (Y, Cr, Cb) 構成, 前面提到過, Y 通常是每點採樣一次, 而 Cr,
Cb 一般是 2x2 點採樣一次, 當然也有的 JPG 是逐點採樣, 或者每兩點採樣 (橫向
兩點, 縱向一點) 採樣係數均被定義成對比最高採樣係數的相對值.

一般情況 (即: Y 逐點採樣, Cr Cb 每 2x2 點一次) 下: Y 有最高的採樣率, 橫向採
樣係數HY=2 縱向採樣係數 VY=2; Cb 的橫向採樣係數 HCb=1, 縱向採樣係數 VCb=1;
同樣 HCr=1, VCr=1

在 Jpeg 裏, 8x8 個原始數據, 經過 RLC, Huffman 編碼後的一串數據流稱爲一個
Data Unit (DU) JPG 裏按 DU 爲單位的編碼次序如下:

1) for (counter_y=1;counter_y<=VY;counter_y++)
for (counter_x=1;counter_x<=HY;counter_x++)
{ 對 Y 的 Data Unit 編碼 }

2) for (counter_y=1;counter_y<=VCb ;counter_y++)
for (counter_x=1;counter_x<=HCb;counter_x++)
{ 對 Cb 的 Data Unit 編碼 }

3) for (counter_y=1;counter_y<=VCr;counter_y++)
for (counter_x=1;counter_x<=HCr;counter_x++)
{ 對 Cr 的 Data Unit 編碼 }

按我上面的例子: (HY=2, VY=2 ; HCb=VCb =1, HCr,VCr=1) 就是這樣一個次序
YDU,YDU,YDU,YDU,CbDU,CrDU
這些就描述了一塊 16x16 的圖形. 16x16 = (Hmax*8 x Vmax*8) 這裏 Hmax=HY=2
Vmax=VY=2

一個 (Hmax*8,Vmax*8) 的塊被稱作 MCU (Minimun Coded Unix) 前面例子中一個
MCU = YDU,YDU,YDU,YDU,CbDU,CrDU

如果 HY =1, VY=1
HCb=1, VCb=1
HCr=1, VCr=1
這樣 (Hmax=1,Vmax=1), MCU 只有 8x8 大, MCU = YDU,CbDU,CrDU

對於灰度 JPG, MCU 只有一個 DU (MCU = YDU)

JPG 文件裏, 圖象的每個組成部分的採樣係數定義在 SOF0 (FFC0) 標記後

簡單說一下 JPG 文件的解碼
-------------------------
解碼程序閒從 JPG 文件中讀出採樣係數, 這樣就知道了 MCU 的大小, 算出整個圖象
有幾個 MCU. 解碼程序再循環逐個對 MCU 解碼, 一直到檢查到 EOI 標記. 對於每個
MCU, 按正規的次序解出每個 DU, 然後組合, 轉換成 (R,G,B) 就 OK 了

附:JPEG 文件格式
~~~~~~~~~~~~~~~~

- 文件頭 (2 bytes): $ff, $d8 (SOI) (JPEG 文件標識)
- 任意數量的段 , 見後面
- 文件結束 (2 bytes): $ff, $d9 (EOI)

段的格式:
~~~~~~~~~

- header (4 bytes):
$ff 段標識
n 段的類型 (1 byte)
sh, sl 該段長度, 包括這兩個字節, 但是不包括前面的 $ff 和 n.
注意: 長度不是 intel 次序, 而是 Motorola 的, 高字節在前,
低字節在後!
- 該段的內容, 最多 65533 字節

注意:
- 有一些無參數的段 (下面那些前面註明星號的)
這些段沒有長度描述 (而且沒有內容), 只有 $ff 和類型字節.
- 每一個段結束到下一個 $ff 間的數據都是合法的, 必須被忽略掉.

段的類型:
~~~~~~~~~

*TEM = $01 可以忽略掉

SOF0 = $c0 幀開始 (baseline JPEG), 細節附後
SOF1 = $c1 dito
SOF2 = $c2 通常不支持
SOF3 = $c3 通常不支持

SOF5 = $c5 通常不支持
SOF6 = $c6 通常不支持
SOF7 = $c7 通常不支持

SOF9 = $c9 arithmetic 編碼(Huffman 的一種擴展算法), 通常不支持
SOF10 = $ca 通常不支持
SOF11 = $cb 通常不支持

SOF13 = $cd 通常不支持
SOF14 = $ce 通常不支持
SOF14 = $ce 通常不支持
SOF15 = $cf 通常不支持

DHT = $c4 定義 Huffman Table, 細節附後
JPG = $c8 未定義/保留 (引起解碼錯誤)
DAC = $cc 定義 Arithmetic Table, 通常不支持

*RST0 = $d0 RSTn 用於 resync, 通常被忽略
*RST1 = $d1
*RST2 = $d2
*RST3 = $d3
*RST4 = $d4
*RST5 = $d5
*RST6 = $d6
*RST7 = $d7

SOI = $d8 圖片開始
EOI = $d9 圖片結束
SOS = $da 掃描行開始, 細節附後
DQT = $db 定義 Quantization Table, 細節附後
DNL = $dc 通常不支持, 忽略
DRI = $dd 定義重新開始間隔, 細節附後
DHP = $de 忽略 (跳過)
EXP = $df 忽略 (跳過)

APP0 = $e0 JFIF APP0 segment marker (細節略)
APP15 = $ef 忽略

JPG0 = $f0 忽略 (跳過)
JPG13 = $fd 忽略 (跳過)
COM = $fe 註釋, 細節附後

其它的段類型都保留必須跳過

SOF0: Start Of Frame 0:
~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $c0 (SOF0)
- 長度 (高字節, 低字節), 8+components*3
- 數據精度 (1 byte) 每個樣本位數, 通常是 8 (大多數軟件不支持 12 和 16)
- 圖片高度 (高字節, 低字節), 如果不支持 DNL 就必須 >0
- 圖片寬度 (高字節, 低字節), 如果不支持 DNL 就必須 >0
- components 數量(1 byte), 灰度圖是 1, YCbCr/YIQ 彩色圖是 3, CMYK 彩色圖
是 4
- 每個 component: 3 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
- 採樣係數 (bit 0-3 vert., 4-7 hor.)
- quantization table 數

DRI: Define Restart Interval:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $dd (DRI)
- 長度 (高字節, 低字節), 必須是 4
- MCU 塊的單元中的重新開始間隔 (高字節, 低字節),
意思是說, 每 n 個 MCU 塊就有一個 RSTn 標記.
第一個標記是 RST0, 然後是 RST1 等, RST7 後再從 RST0 重複

DQT: Define Quantization Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $db (DQT)
- 長度 (高字節, 低字節)
- QT 信息 (1 byte):
bit 0..3: QT 號(0..3, 否則錯誤)
bit 4..7: QT 精度, 0 = 8 bit, 否則 16 bit
- n 字節的 QT, n = 64*(精度+1)

評論:
- 一個單獨的 DQT 段可以包含多個 QT, 每個都有自己的信息字節
- 當精度=1 (16 bit), 每個字都是高位在前低位在後

DAC: Define Arithmetic Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
法律原因, 現在的軟件不支持 arithmetic 編碼.
不能生產使用 arithmetic 編碼的 JPEG 文件

DHT: Define Huffman Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $c4 (DHT)
- 長度 (高字節, 低字節)
- HT 信息 (1 byte):
bit 0..3: HT 號 (0..3, 否則錯誤)
bit 4 : HT 類型, 0 = DC table, 1 = AC table
bit 5..7: 必須是 0
- 16 bytes: 長度是 1..16 代碼的符號數. 這 16 個數的和應該 <=256
- n bytes: 一個包含了按遞增次序代碼長度排列的符號表
(n = 代碼總數)

評論:
- 一個單獨的 DHT 段可以包含多個 HT, 每個都有自己的信息字節

COM: 註釋:
~~~~~~~~~~

- $ff, $fe (COM)
- 註釋長度 (高字節, 低字節) = L+2
- 註釋爲長度爲 L 的字符流

SOS: Start Of Scan:
~~~~~~~~~~~~~~~~~~~

- $ff, $da (SOS)
- 長度 (高字節, 低字節), 必須是 6+2*(掃描行內組件的數量)
- 掃描行內組件的數量 (1 byte), 必須 >= 1 , <=4 (否則是錯的) 通常是 3
- 每個組件(部分): 2 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), 見 SOF0
- 使用的 Huffman 表00-1-14:
- bit 0..3: AC table (0..3)
- bit 4..7: DC table (0..3)
- 忽略 3 bytes (???)
發佈了15 篇原創文章 · 獲贊 1 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章