jpeg壓縮算法

jpeg的壓縮分爲四個步驟

首先明確jpeg一般是將bmp轉爲jpeg格式的,那麼我們就需要清楚bmp和jpeg的文件架構

以下是bmp的文件架構

項目
位圖文件頭
位圖信息頭
彩色表/調色板
位圖數據

在這裏插入圖片描述
1.bmp文件頭
在這裏插入圖片描述
2位圖信息頭
在這裏插入圖片描述
3彩色表/調色板
在這裏插入圖片描述
索引:(藍,綠,紅,Alpha)

0號:(fe,fa,fd,00)

1號:(fd,f3,fc,00)

2號:(f4,f3,fc,00)

3號:(fc,f2,f4,00)

4號:(f6,f2,f2,00)

5號:(fb,f9,f6,00) 等等。

4位圖數據
在這裏插入圖片描述
以下是jpeg的文件架構

在這裏插入圖片描述
在這裏插入圖片描述
四個步驟

1將RGB轉化爲yCbCR

YCbCR中的y代表亮度,cb,cr代表綠色和紅色的色差,用這種表示方法能夠很好的將圖的細節區分開來
轉換公式爲
在這裏插入圖片描述
這一部分的代碼如下:

 for(int i = height - 1; i >= 0; i--)
			 {
				 for(int j = 0; j < width; j++)
				 {
					int blue = dis.read();
					int green = dis.read();
					int red = dis.read();
					int y = (int) (0.299 * (double)red + 0.587 * (double)green + 0.114 * (double)blue) -128;
					imageY[i][j] = y;
					imagecb[i][j] =  (int) (-0.1687 * (double)red - 0.3313 * (double)green + 0.5 * (double)blue);
					imagecr[i][j] =  (int) (0.5 * (double)red - 0.4187 * (double)green - 0.0813 * (double)blue);
				 }
			 }

經過j這一步我們能得到3張二維矩陣,分別是y(亮度)矩陣,cb(綠色)矩陣,cr(紅色)矩陣

2.DCT(離散餘弦變換變換)

爲了能更好的處理信息,我們需要將yCbCR進行二維的離散餘弦變換,公式如下:
在這裏插入圖片描述
轉換爲之後我們就會發現圖像中的低頻的信息集中在矩陣的左上角,高頻信息集中在右下角,而我們人眼是對低頻信息敏感的。
這是對lena左上角的Y矩陣dct轉換過程
在這裏插入圖片描述
代碼:

	public static int[] Dct(int posy, int posx, int preData[][], int aux[])
	{
		int res[] = new int[70];
		for(int v=0; v<8; v++)
		{
			for(int u=0; u<8; u++)
			{
				double alpha_u = (u==0) ? 1/Math.sqrt(8.0) : 0.5;
				double alpha_v = (v==0) ? 1/Math.sqrt(8.0) : 0.5;

				double sum = 0;
				for(int x=0; x<8; x++)
				{
					for(int y=0; y<8; y++)
					{
						double temp = preData[posy + y][posx + x];
						temp *= Math.cos((2*x+1)*u*PI/16.0);
						temp *= Math.cos((2*y+1)*v*PI/16.0);
						sum += temp;
					}
					
				
				}
				sum *= alpha_u*alpha_v/aux[ZigZag[v][u]];
				res[ZigZag[v][u]] = (int)sum;
			}
		}
		
		return res;
	}

3.數據量化

這一部就是進一步將數據進行簡略,爲了使得處理後的數據更真實jpeg給我們提供了兩張量化表,一張是標準亮度量化表,一張是標準色差量化表
在這裏插入圖片描述
在這裏插入圖片描述
公式如下
在這裏插入圖片描述
這一步的代碼我寫在了dct裏面.

4.哈夫曼

將數據進一步處理後按照不同信息的出現頻率不同重新編碼
我認爲這一步是最難的,需要處理很多細節,比如根據jpeg提供的標準生成哈夫曼表
我們首先要將上一步的數據用zigzag掃描變成一維矩陣,用zigzag的好處是能使數據中的低頻信息集中在一維矩陣的前面。
然後對一位矩陣進行分塊。將矩陣中非零數據以及前面的0作爲一個處理單元,如果某個單元的0的個數超過16,則是16爲一個單元。接着用jpeg提供的一張標準的碼錶來對數據進行編碼,這裏主要是對非0數據進行編碼

Value Size Bits
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 0 0000,…,0 1111 1 0000,…,1 1111
-63,…,-32 32,…,63 6 00 0000,… …,11 1111
-127,…,-64 64,…,127 7 000 0000,… …,111 1111
-255,…,-128 128,…,255 8 0000 0000,… …,1111 1111
-511,…,-256 256,…,511 9 0 0000 0000,… …,1 1111 1111
-1023,…,-512 512,…,1023 10 00 0000 0000,… …,11 1111 1111
-2047,…,-1024 1024,…,2047 11 000 0000 0000,… …,111 1111 1111

然後對0的個數和非0數據編碼的長度進行編碼,這裏用到了jpeg提供的哈夫曼編碼;

Length Value Bits
3 bits 04 05 03 02 06 01 00 (EOB) 000 001 010 011 100 101 110
4 bits 07 1110
5 bits 08 1111 0
6 bits 09 1111 10
7 bits 0A 1111 110
8 bits 0B 1111 1110

代碼:

public BitPack[] HandleHuff(int data[], int preDc[],BitPack[] dataDc,BitPack[] dataAc)
	{
		BitPack EOBFlag = dataAc[0X00];
		BitPack MoreZeroFlag = dataAc[0xF0];
		BitPack outRes[] = new BitPack[256];
		int index = 0,endPos = 63;
		//------
		int dcRes = data[0] - preDc[0];
		preDc[0] = data[0];
		if(dcRes == 0)
		{
			outRes[index] = new BitPack();
			outRes[index] = dataDc[0];
			index++;
		}
		else
		{
			
			BitPack bp = ValueToBitPack(dcRes);
			outRes[index] = new BitPack();
			outRes[index] = dataDc[bp.len]; index++;
			outRes[index] = new BitPack();
			outRes[index] = bp;index++;
			
		}
		
		while((endPos > 0) && (data[endPos] == 0)) endPos--;

		for(int i=1; i<=endPos; )
		{
			int startPos = i;
			while((data[i] == 0) && (i <= endPos)) i++;

			int zeroCounts = i - startPos;
			if (zeroCounts >= 16)
			{
				for (int j=1; j<=zeroCounts/16; j++)
					outRes[index] = new BitPack();
					outRes[index] = MoreZeroFlag;index++;
				zeroCounts = zeroCounts%16;
			}

			BitPack bp = ValueToBitPack(data[i]);
			outRes[index] = new BitPack();
			outRes[index] = dataAc[(zeroCounts << 4) | bp.len];index++;
			outRes[index] = new BitPack();
			outRes[index] = bp;index++;
			i++;
		}

		if (endPos != 63)
		{
			outRes[index] = EOBFlag;index++;
		}
		bitPackNums = index;
		return outRes;
	}

以上就是整個jpeg的壓縮過程
源文件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章