免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

JPEG圖像壓縮詳解和代碼實現(xiàn)

 東西二王 2023-02-16 發(fā)布于重慶

一、圖像存儲

為了有效的傳輸和存儲圖像,需要對圖像數(shù)據(jù)進行壓縮。依據(jù)圖像的保真度,圖像壓縮可分為無損壓縮和有損壓縮。

1. 無損壓縮

無損壓縮的基本原理是相同的顏色信息只需保存一次。無損壓縮保證解壓以后的數(shù)據(jù)和原始數(shù)據(jù)完全一致,壓縮時去掉或減少數(shù)據(jù)中的冗余,解壓時再重新插到數(shù)據(jù)中,是一個可逆過程。無損壓縮算法一般可以把普通文件的數(shù)據(jù)壓縮到原來的1/2-1/4。

2. 有損壓縮

有損壓縮方式在解壓后圖像像素值會發(fā)生改變,解壓以后的數(shù)據(jù)和原始數(shù)據(jù)不完全一致,是不可逆壓縮方式。在保存圖像時保留了較多的亮度信息,將冗余信息合并,合并的比例不同,壓縮的比例也就不同。由于信息量減少了,所以壓縮比可以很高,圖像質(zhì)量也會下降。

二、圖像格式

常見有損的圖像格式有:JPEG、WebP,常見無損的圖像格式有:PNG、BMP、GIF。

通常以文件的后綴名來區(qū)分圖片的格式,但有時并不準確。實際的圖片格式可通過查看圖片數(shù)據(jù)來確定(查看方式:Notepad 打開圖片,選擇“插件”->“插件管理”,安裝“HEX-Editor”,安裝后再次選擇“插件”->“HEX-Editor”->“View in HEX”)。

以JPEG和PNG圖像格式為例。JPEG格式以0xFF D8開頭,以0xFF D9結(jié)尾。PNG格式以0x89 50 4E 47 0D 0A 1A 0A開頭,其中50 4E 47是英文字符串“PNG”的ASCII碼,以00 00 00 00 49 45 4E 44 AE 42 60 82結(jié)尾,標志著PNG數(shù)據(jù)流結(jié)束。

文章圖片1

三、JPEG壓縮

上文的圖例是圖像文件實際保存的數(shù)據(jù),也就是圖像壓縮后的數(shù)據(jù)。本文以JPEG格式為例講解圖像壓縮的過程。JPEG的文件格式一般有兩種文件擴展名:.jpg和.jpeg,這兩種擴展名的實質(zhì)是相同的,我們可以把.jpg的文件改名為.jpeg,而對文件本身不會有任何影響。嚴格來講,JPEG的文件擴展名應(yīng)該為.jpeg,由于DOS時代的8.3文件名命名原則,就使用了.jpg的擴展名。

下文以小狗圖像為例,詳述圖片壓縮具體過程,圖像分辨率是320x264。首先看下圖:

文章圖片2

通常我們看到的彩色圖像是三通道或四通道圖像。三通道圖像是指有RGB三個通道,R:紅色,G:綠色,B:藍色。四通道圖像是在三通道的基礎(chǔ)上加了Alpha通道,Alpha通道用來衡量一個像素的透明度。當Alpha為0時,該像素完全透明;當Alpha為255時,該像素完全不透明。四通道圖像只有PNG格式支持。

圖中小狗是三通道圖像,有320x264個像素點,每個像素點由三個值表示,如上圖右側(cè)小狗眼睛部分,黑色區(qū)域每個通道的像素值較小如(3,2,11),白點部分像素值較高如(114,116,117)。圖中共84480個像素,每個像素用24位表示,若直接存儲需要占用84480*24/8/1024=247.5KB,為了有效地傳輸和存儲圖像,有必要對圖像做壓縮。JPEG壓縮步驟如下。

1. 色彩空間轉(zhuǎn)換

JPEG采用YUV顏色空間,“Y”表示明亮度,也就是灰度值;“U”和“V”表示色度,用于描述圖像色彩和飽和度。因為人眼對亮度比較敏感,而對于色度不那么敏感,可以在UV維度大量縮減信息,所以先將RGB的數(shù)據(jù)轉(zhuǎn)換到Y(jié)UV色彩空間。轉(zhuǎn)換公式:

  • Y = 0.299R 0.587G 0.114B
  • U = 0.5R - 0.4187G - 0.0813G 128
  • V = -0.1687R - 0.3313G 0.5B 128

python 實現(xiàn)

import cv2import numpy as np# opencv 讀取的圖片是BGR順序image = cv2.imread('data/dog.jpg')h, w, c = image.shape# 色彩空間轉(zhuǎn)換 BGR -> YUVimage_yuv = np.zeros_like(image, dtype=np.uint8)for line in range(h): for row in range(w): B = image[line, row, 0] G = image[line, row, 1] R = image[line, row, 2] Y = np.round(0.299*R 0.587*G 0.114*B) U = np.round(0.5*R - 0.4187*G - 0.0813*G 128) V = np.round(-0.1687*R - 0.3313*G 0.5*B 128) image_yuv[line, row, :] = (Y, U, V)# 保存圖像cv2.imwrite('Y.png', image_yuv[:,:, 0])cv2.imwrite('U.png', image_yuv[:,:, 1])cv2.imwrite('V.png', image_yuv[:,:, 2]) cv2.imwrite('YUV.png', image_yuv)

結(jié)果展示

文章圖片3

2. 降采樣

由于人眼對色度不敏感,直接將U、V分量進行色度采樣,JPEG壓縮算法采用YUV 4:2:0的色度抽樣方法。4:2:0表示對于每行掃描的像素,只有一種色度分量以2:1的抽樣率存儲,也就是說每隔一行/列取值,偶數(shù)行取U值,奇數(shù)行取V值,UV通道寬度和高度分別降低為原來的1/2。

文章圖片4

python 實現(xiàn)

# 色彩空間轉(zhuǎn)換 BGR -> YUV 4:2:0def RGB2YUV420(image):    h, w, c = image.shape    image_y = np.zeros((h, w), dtype=np.uint8)    image_u = np.zeros(((h-1)//2 1, (w-1)//2 1), dtype=np.uint8)    image_v = np.zeros(((h-1)//2 1, (w-1)//2 1), dtype=np.uint8)    for line in range(h):        for row in range(w):            B = image[line, row, 0]            G = image[line, row, 1]            R = image[line, row, 2]            Y = np.round(0.299*R   0.587*G   0.114*B)            image_y[line, row] = Y            if line % 2 == 0 and row % 2 == 0:                U = np.round(0.5*R - 0.4187*G - 0.0813*G   128)                image_u[line//2, row//2] = U             if line % 2 == 1 or line == h-1:                V = np.round(-0.1687*R - 0.3313*G   0.5*B   128)                image_v[line//2, row//2] = V    return image_y, image_u, image_v

結(jié)果展示

文章圖片5

3. 離散余弦變換(DCT)

人類視覺對高頻信息不敏感,利用離散余弦變換可分析出圖像中高低頻信息含量,進而壓縮數(shù)據(jù)。

JPEG中將圖像分為8*8的像素塊,對每個像素塊利用離散余弦變換進行頻域編碼,生成一個新的8*8的數(shù)字矩陣。對于不能被8整除的圖像大小,需對圖像填充使其可被8整除,通常使用0填充。由于離散余弦變換需要定義域?qū)ΨQ,所以先將矩陣中的數(shù)值左移128,使值域范圍在[-128, 127]。

二維離散余弦變換公式為:

文章圖片6
文章圖片7

python 實現(xiàn)

import mathdef alpha(u): if u==0: return 1/np.sqrt(8) else: return 1/2def block_fill(block): block_size = 8 dst = np.zeros((block_size, block_size), dtype=np.uint8) h, w = block.shape dst[:h, :w] = block return dstdef DCT_block(img): block_size = 8 img = block_fill(img) img_fp32 = img.astype(np.float32) img_fp32 -= 128 img_dct = np.zeros((block_size, block_size), dtype=np.float32) for line in range(block_size): for row in range(block_size): n = 0 for x in range(block_size): for y in range(block_size): n = img_fp32[x,y]*math.cos(line*np.pi*(2*x 1)/16)*math.cos(row*np.pi*(2*y 1)/16) img_dct[line, row] = alpha(line)*alpha(row)*n return np.ceil(img_dct) def DCT(image): block_size = 8 h, w = image.shape dlist = [] for i in range((h block_size - 1) // block_size): for j in range((w block_size - 1) // block_size): img_block = image[i*block_size:(i 1)*block_size, j*block_size:(j 1)*block_size] # 處理一個像素塊 img_dct = DCT_block(img_block) dlist.append(img_dct) return dlistimg_dct = DCT(image_y)

結(jié)果展示

文章圖片8

4. 量化

每個8*8的像素塊經(jīng)離散余弦變換后生成一個8*8的浮點數(shù)矩陣,量化的過程則是去除矩陣中的高頻信息,保留低頻信息。JPEG算法提供了兩張標準化系數(shù)矩陣,分別處理亮度數(shù)據(jù)和色差數(shù)據(jù),表示 50% 的圖像質(zhì)量。

文章圖片9

量化的過程:使用DCT變換后的浮點矩陣除以量化表中數(shù)值,然后取整。量化表是控制JPEG壓縮比的關(guān)鍵,可以根據(jù)輸出圖片的質(zhì)量來自定義量化表,通常自定義量化表與標準量化表呈比例關(guān)系,表中數(shù)字越大則質(zhì)量越低,壓縮率越高。

python 實現(xiàn)

def quantization(blocks, Q):    img_quan = []    for block in blocks:        img_quan.append(np.round(np.divide(block, Q)))    return img_quanimg_quan = quantization(img_dct, Qy)

結(jié)果展示

文章圖片10

5. ZIGZAG排序

排序規(guī)則如圖:

文章圖片11

python 實現(xiàn)

def zigzag(blocks): block_list = [] for block in blocks: zlist = [] w, h = block.shape if w != h: return None max_sum = w h - 2 for _s in range(max_sum 1): if _s % 2 == 0: for i in range(_s, -1, -1): j = _s - i if i >= w or j >= h: continue zlist.append(block[i,j]) else: for j in range(_s, -1, -1): i = _s - j if i >= w or j >= h: continue zlist.append(block[i,j]) block_list.append(zlist) return block_listzglist = zigzag(img_quan)

結(jié)果展示

[39.0, 4.0, -4.0, 0.0, -0.0, 2.0, -2.0, -1.0, -1.0, -1.0, 0.0, -0.0, -0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.0, -0.0, 0.0, 0.0, -0.0, 0.0, -0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.0, -0.0, 0.0, -0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

6. 差分脈沖編碼調(diào)制(DPCM)對直流系數(shù)(DC)編碼

對像素矩陣做DCT變換,相當于將矩陣的能量壓縮到第一個元素中,左上角第一個元素被稱為直流(DC)系數(shù),其余的元素被稱為交流(AC)系數(shù)。JPEG將量化后的頻域矩陣中的DC系數(shù)和AC系數(shù)分開編碼。使用DPCM技術(shù),對相鄰圖像塊量化DC系數(shù)的差值進行編碼;使用行程長度編碼(RLE)對AC系數(shù)編碼。需要注意的一點是,對AC系數(shù)的的RLE編碼是在8x8的塊內(nèi)部進行的,而對DC系數(shù)的DPCM編碼是在整個圖像上若干個8x8的塊之間進行的。

差值編碼原理:樣值與前一個(相鄰)樣值的差值,則這些差值大多數(shù)是很小的或為零,可以用短碼來表示;而對于出現(xiàn)幾率較差的差值,用長碼表示,這樣可以使總體碼數(shù)下降;采用對相鄰樣值差值進行變字節(jié)長編碼的方式稱為差值編碼,又稱為差分脈碼調(diào)制(DPCM)。

8x8的圖像塊經(jīng)過DCT變換后,得到的直流系數(shù)特點:

  • 系數(shù)值較大;
  • 相鄰圖像塊的系數(shù)值變換不大。

python 實現(xiàn)

def DPCM(zglist):    res_dpcm = []    for i in range(len(zglist)):        if i == 0:            res_dpcm.append(zglist[i][0])            continue        res_dpcm.append(zglist[i][0]-zglist[i-1][0])    return res_dpcmres_dpcm = DPCM(zglist)

結(jié)果展示

[50.0, -2.0, -13.0, -7.0, -3.0, 0.0, -1.0, 0.0, -1.0, -2.0, -0.0, -1.0, 0.0, -1.0, -0.0, -1.0, 0.0, -0.0, -0.0, -0.0, -0.0, -0.0, 0.0, -0.0, -0.0, ..., -0.0, 0.0, -0.0, 0.0, -0.0]

7. DC系數(shù)中間格式

JPEG中為了更進一步節(jié)約空間,不直接保存數(shù)據(jù)的具體數(shù)值,而是將數(shù)據(jù)按照位數(shù)分為16組,保存在表里面。這也就是所謂的變長整數(shù)編碼VLI。編碼VLI表如下:

文章圖片12

以第一個block和第二個block為例,DPCM結(jié)果是50,通過查找VLI編碼表該值位于VLI表格的第6組,因此可以寫成(6)(50)的形式,即為DC系數(shù)的中間格式。

8. 行程長度編碼(RLC)對交流系數(shù)(AC)編碼

具有相同顏色并且是連續(xù)的像素數(shù)目稱為行程長度。RLC編碼簡單直觀,編碼/解碼速度快。例如,字符串AAABCDDDDDDDDBBBBB 利用RLE原理可以壓縮為3ABC8D5B。在JPEG編碼中,使用的數(shù)據(jù)對是(兩個非零AC系數(shù)之間連續(xù)0的個數(shù),下一個非零AC系數(shù)的值)。注意,如果AC系數(shù)之間連續(xù)0的個數(shù)超過16,則用一個擴展字節(jié)(15,0)來表示16連續(xù)的0。

python 實現(xiàn)

def rlc(zglist): res_ac = [] for i in range(len(zglist)): ac = [] zg = zglist[i] zero_num = 0 for k in range(1, len(zg)): if zg[k] != 0: ac.append((zero_num, zg[k])) zero_num = 0 else: zero_num = 1 if zero_num: ac.append((0, 0)) res_ac.append(ac) return res_acres_ac = rlc(zglist)

結(jié)果展示

zigzag結(jié)果:[50.0, -2.0, -13.0, -7.0, -3.0, 0.0, -1.0, 0.0, -1.0, -2.0, -0.0, -1.0, 0.0, -1.0, -0.0, -1.0, 0.0, -0.0, -0.0, -0.0, -0.0, -0.0, 0.0, -0.0, -0.0, ..., -0.0, 0.0, -0.0, 0.0, -0.0]

RLC編碼結(jié)果:[(0, -2.0), (0, -13.0), (0, -7.0), (0, -3.0), (1, -1.0), (1, -1.0), (0, -2.0), (1, -1.0), (1, -1.0), (1, -1.0), (0, 0)]

9. AC系數(shù)中間格式

RLC編碼結(jié)果:[(0, -2.0), (0, -13.0), (0, -7.0), (0, -3.0), (1, -1.0), (1, -1.0), (0, -2.0), (1, -1.0), (1, -1.0), (1, -1.0), (0, 0)]

對每組數(shù)據(jù)第二個數(shù)進行VLI編碼,(0, -2.0)第二個數(shù)是-2.0,查找VLI編碼表是第2組,所以可將其寫(0, 2), -2.0。同理,AC系數(shù)中間格式可寫成以下形式:

(0, 2), -2.0, (0, 4), -13.0, (0, 3), -7.0, (0, 2), -3.0, (1, 1), -1.0, (1, 1), -1.0, (0, 2), -2.0, (1, 1), -1.0, (1, 1), -1.0, (1, 1), -1.0, (0, 0)

10. 熵編碼

JPEG基本系統(tǒng)規(guī)定采用Huffman編碼。Huffman編碼時DC系數(shù)與AC系數(shù)分別采用不同的Huffman編碼表,對于亮度和色度也采用不同的Huffman編碼表。因此,需要4張Huffman編碼表才能完成熵編碼的工作。具體的Huffman編碼采用查表的方式來高效地完成。

上文中8x8像素塊的中間格式:

  • DC: (6)(50),數(shù)字6查DC亮度Huffman編碼表是1110,數(shù)字50查VLI編碼表是110010。
  • AC: (0, 2), -2.0, (0, 4), -13.0, (0, 3), -7.0, (0, 2), -3.0, (1, 1), -1.0, (1, 1), -1.0, (0, 2), -2.0, (1, 1), -1.0, (1, 1), -1.0, (1, 1), -1.0, (0, 0),(0,2)查AC亮度Huffman編碼表是01,-2.0查VLI編碼表是01。

因此,這個8x8的亮度像素塊信息壓縮后的數(shù)據(jù)流為1110110010,0101,10110010,100000,0100,11000,11000,0101,11000,11000,11000,1010??偣?5比特,壓縮比為(64*8-65)/(64*8)*100%=87.3%

以上是JPEG壓縮的整個過程,最終將所有編碼結(jié)果整合并按JPEG規(guī)范格式存儲,即可得到j(luò)pg格式的圖像文件。

文章圖片13

智驅(qū)力-科技驅(qū)動生產(chǎn)力

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多