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数据进行编码

ValueSizeBits
00
-1 110 1
-3,-2 2,3200,01 10,11
-7,-6,-5,-4 4,5,6,73000,001,010,011 100,101,110,111
-15,…,-8 8,…,1540000,…,0111 1000,…,1111
-31,…,-16 16,…,3150 0000,…,0 1111 1 0000,…,1 1111
-63,…,-32 32,…,63600 0000,… …,11 1111
-127,…,-64 64,…,1277000 0000,… …,111 1111
-255,…,-128 128,…,25580000 0000,… …,1111 1111
-511,…,-256 256,…,51190 0000 0000,… …,1 1111 1111
-1023,…,-512 512,…,10231000 0000 0000,… …,11 1111 1111
-2047,…,-1024 1024,…,204711000 0000 0000,… …,111 1111 1111

然后对0的个数和非0数据编码的长度进行编码,这里用到了jpeg提供的哈夫曼编码;

LengthValueBits
3 bits04 05 03 02 06 01 00 (EOB)000 001 010 011 100 101 110
4 bits071110
5 bits081111 0
6 bits091111 10
7 bits0A1111 110
8 bits0B1111 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的压缩过程
源文件

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值