【基于Huffman的图像压缩处理】 c++ jpeg 同济大学

(一)如何使用Huffman编码进行图像压缩

您好! 这是我的第一篇 CSDN 文章。如有问题请多包涵!
本文是使用范式Huffman的算法进行对图像压缩的讲解,它和普通的Huffman压缩文本有一定区别。大致内容包括
1.频域编码初步
2.jpg图像的压缩(思路及步骤)
3.jpg编码
4.附录(步骤,源码)

(二)压缩实现

2.1.频域编码的讲解

什么是频域编码算法
或称变换编码,这是最常用的方法。首先使用如傅里叶变换、离散余弦变换(DCT)或者小波变换这样的傅立叶相关变换,然后进行量化和用熵编码法压缩。
什么是傅里叶变换
简而言之,傅里叶变换把一个输入信号分解成一堆正弦波的叠加。

举个例子,你要做一道番茄炒蛋,但是不太清楚番茄和鸡蛋分别加多少,那么傅里叶变换就是替你找到他们(正弦函数)之间较好的配比

在这里插入图片描述
比如这里的方波,理论上可以使用无限多的正弦波来完美地表达一
个方波。

那么类比在我们的图像压缩上则可表示为如下效果:
在这里插入图片描述
我们压缩的思想之一就是 可以用一些像素块(压缩后的产品)来粗略的显示图片的原貌,随着这些像素块越多,或者选取的质量越好,我们的图像就可以越还原。
在这里插入图片描述
压缩包含的另一个思想呢就是将字符进行Huffman压缩,因为jpg文件使用二进制打开后仍然是一堆字符串。至于Huffman是如何对字符进行压缩的,本文不再讨论说明。请读者移步其他文章,因为网上实在有太多的讲解文章。

2.2jpg图像的压缩(思路及步骤)

2.2.1 什么是jpg

JPEG是JPEG标准的产物,该标准由国际标准化组织制订,是面向连续色调静止图像的一种压缩标准
JPEG格式是最常用的图像文件格式,后缀名为.jpg或.jpeg。

此外我们需知道一个图片文件中,它的中间字符无非是在记录每一个像素点的信息,而每一个像素则是由RGB(红绿蓝比例)来进行数值表示的。

补充:jpg和png的区别联系
000000000000000000000000000000000000000000

2.2.2 如何实现jpg

整体思路:①提取图片的信息②略去不重要信息③保留展示重要信息

具体详细步骤
①图像分割
②RGB->YCbCr
③DCT 离散余弦变换
④数据量化+Zigzag提取
⑤Huffman编码
⑥写入文件

这里可能有着你没听/见过的东西,但是不懂也没关系,下文都有通俗的语言讲解。

2.2.2.1图像分割

图像分割的意义(好处)
在这里插入图片描述

2.2.2.2RGB->YCbCr

这里的三个核心点:
什么是RGB?
什么是YCbCr?
为什么要转换?

将图像的颜色信息从红绿蓝(RGB)颜色空间转换为亮度(Y)和色度(Cb和Cr)(Cb和Cr分别表示蓝色和红色的“色差值”)颜色空间。这个转换减少了冗余信息,因为人眼对亮度更敏感,色度可以更粗略地表示颜色。

怎么转换?
直接用公式:
Y = 0.29871R + 0.58661G + 0.11448B
Cb = -0.16874
R - 0.33126G + 0.50000B
Cr = 0.50000R - 0.41869G - 0.08131*B

2.2.2.3DCT 离散余弦变换

离散余弦变换(DCT),是一种数学(傅里叶的一种)变换,它帮助我们更有效地表示图像的信息。现在,让我们用通俗易懂的语言来解释这个过程。

想象一下,你有一张图像,划分成很多小块,每一块都有不同的颜色和亮度。而离散余弦变换的目标就是找出每个小块中的“颜色变化”。

在这个变换中,我们不再关注每个像素点的具体颜色值,而是转而关注图像中颜色的变化。它会将图像分解成一系列波的组合,每个波代表不同频率的颜色变化

类比线性代数
在这里插入图片描述
我们可以把那些竖着的,理解为基向量。任何的在它们所可以形成的空间内的向量,都可以由他们来线性表示。我们把第一个向量叫做直流数据,简写成DC,后面的叫做交流数据,写为AC。

作用呢?
我们可以通过保存系数来记录向量x,利用新的数(系数)来代表原来的数(这里的向量就是上面所获得的图片YCbCr数据)。那么我们不就更简单的表示出了数据吗?

核心:如何进行变换呢?
我们的Y、Cb、Cr分别是以8*8二位数据存储的,那么我们就要用二维的DCT来处理。利用刚刚的思路,我们只想要系数F(u,v)。直接套公式:
在这里插入图片描述
好处的直接体现:
在这里插入图片描述
DCT处理后的数据看起来简洁了许多?然而我们知道 实际过程往往不如所愿,怎么可能都是那么美妙的数据。这里就如番茄鸡蛋一样,量化和变换需要搭配着才更完美。

2.2.2.4数据量化+Zigzag提取

简单说量化的过程相当于忽略了图像中的一些微小变化,保留了相对更大的、对图像质量更为重要的信息。

DCT变换之后,我们得到了一系列的频域系数,它们表示图像中不同频率的颜色变化。但是,并不是所有的系数都对图像的质量有同样的重要性
在量化中,我们通过将这些系数除以一个特定的量化矩阵,然后将一些较小的系数舍弃,从而减少数据量。

代码上的操作步骤:
在这里插入图片描述

别担心!量化表好像不清楚??作者将其放在了后续附录,!附录中还包括了你压缩过程中的许多关键信息,请别忽略!

可视化好处如图:数据集中,省略不重要,留下重要,浮点化整,方便压缩。
在这里插入图片描述
简单的压缩文本可知,连续出现的数据是很好压缩的!现在,我们只需记录下前面的数据,后面甚至可以用一句话就完事:“后面都是0”

Zigzag处理
但是!
好像现在的0没有办法全都聚在最后呢??
就嗯造!

现在是一个二维数组,我们要将其转化为一维数组,并且尽量能使0聚集在一块,我们就可以使用如图所示的方法。可以称其为“Z”字抖动。
在这里插入图片描述

使用一个zigzag的数组,把它的对应位置的值置为上图箭头所到的顺序值。
在这里插入图片描述

再嵌套进去赋值到新的数组
在这里插入图片描述

这样不就得到了按“Z”形取得的数组了吗?
在这里插入图片描述

2.2.2.5Huffman编码

不是简单的Huffman也不仅仅只有范式Huffman。当然懂一般的Huffman思想肯定是对下面理解有帮助的。
有一定难度,配合源码、文档或许能更好理解,最下方附录有链接

使用Huffman之前还需要进行一定的处理 : RLE+bit编码
在我们的处理过后,0这个数据非常多,我们将原始数据分组,将非0数据和前面的0作为一组。如果一个组的数据超过16个0,那么单独编组,最后的尾巴0用“EOB”表示,意思是,后面全是0。
在这里插入图片描述

压缩中的RLE思想!

然后我们先给一个bit表:
在这里插入图片描述
利用bit表对RLE产生的数据进行编码(即bit编码)

在这里插入图片描述
在这里插入图片描述

现在才算开始Huffman编码
在这里插入图片描述
回到图像。
考虑合并后的数据,为他们编码。形成他们的映射关系。
由于Y和CbCr用的是不同的量化表,CbCr用同一张量化表(上文中所说在附录里的东西,没有印象也正常);
又因为DC和AC的数据所表示的范围是不同的(直观来看,DC前面没0,而AC可能有0)所以我们需要为Y、CbCr分别编AC和DC的huffman码
在这里插入图片描述
下面是官方给的表,我们需要利用它进行查表后对应编码
在这里插入图片描述

这里的最后一张图总结该小结(只要能看懂这个图,这部分就算是懂了!)

在这里插入图片描述
sh*t !那Huffman表在哪又怎么查呢?
想一想
我们最后会将数据变成bit码,那如果没有一张表用于记录你的转换规则,那它也就是一堆bit码,解压缩不回去啊!所以我们需要把规定好的Huffman规则给它写到文件里面去,那不就好了吗。并且!我们在进行③到④的过程中严格按照这个规定去查表压缩,那不就ok了?

不如用笨人代码稍微代入一下()
**
规定的表
根据表建树
根据树(表)转换对应的值
**
在这里插入图片描述

在这里插入图片描述
454行对应③到④的0x6—>100 455对应100011–>100011 大概是这么个意思!
在这里插入图片描述

这里不懂那就先不懂吧!接着往后读,读完再结合完整代码理一理可能就通了!

接下来说明范式Huffman的原理
“给我东西我不会用,那么不如不给我好了。” ——鲁迅

huffman表的重要参数之一:编码内容
我们在之前的数组的基础上再给出一个数组,这个新数组的大小由前面给出的数组决定
最上面的数组的意思是说:此哈夫曼树有0+2+2+0+5+1+6+1=17个叶子结点,即本字段应该有17个字节。
00 01 11 02 21 03 31 41 12 51 61 71 81 91 22 13 32 (长度为17)
这段数据表示17个叶子结点按从小到大排列,其权值依次为0、1、11、2、21、3、31、41……
似乎只知道huffman码字的长度,还是不知道具体的值?
在这里插入图片描述
怎么建树
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
如果至此图片还是没能看懂,建议先往下看。等到看源码时再回头过来看这个,可能可以清楚不少。

2.2.2.6写入文件

假设一下,如果我们压缩的最后结果只是将一堆像素点的信息单纯的压缩为了更短的字符串,那么计算机他怎么知道你这个文件是图片格式??

因此压缩的结果文件必然要包含一些其他信息,比方:“这是一张图片”,“这是jpeg的压缩算法”,“这张图片的数据是从哪一个数据到哪一个数据”等等之类的,这样你的计算机才能正确打开这张图片吧?

具体步骤很多,详见下一节

2.2.3 jpg编码

2.2.3.1 文件头介绍

这些都是jpeg的规范标准,所以就嗯写。(凡是嗯写的地方都可以参考附录或者源码)
在这里插入图片描述
JPEG文件使用的数据存储方式有多种。最常用的格式称为JPEG文件交换格式(JPEG
File Interchange Format,JFIF)。而JPEG文件大体上可以分成两个部分:标记码
(Tag)和压缩数据

在这里插入图片描述
注意!BUG来源之一!
在此之前,一个很难察觉的BUG:
微处理机中的存放顺序有正序(big endian)和逆序(little endian)之分。
例如,十六进制数为A02B,正序存放就是A02B,逆序存放就是2BA0。英特尔(Intel)公司
的微处理器使用逆序。JPEG文件中的字节是按照正序排列的。

所以,要把这个两个字节倒过来!但是怎么做呢,有点像一道简单的字符串算法题?
比如可以的操作(当然可以靠读者们自己思考一种更好的办法):
我先拿个东西复制这两个字节的数据,然后再移位,最后分别对这两个数据进行一些位运算,得到结果
譬如:00101111→11110010(这是一个字节的情况)
第一步:复制数据
00101111→ 00101111 00101111
第二步:移位
00101111→ 0000 0010 (1111被移走
00101111→ 1111 0000 (0010被移走
第三步:位或操作
0000 0010
1111 0000

1111 0010
完成!

2.2.3.2写(文件总结构)

重要
SOI,Start of Image,图像开始
APP0,Application,应用程序保留标记0
DQT,Define Quantization Table,
定义量化表 (附录中包含了量化表可以参考)
SOF0,Start of Frame,帧图像开始
DHT,Difine Huffman Table,
定义哈夫曼表(就这有点技术)
SOS,Start of Scan,扫描开始
EOI, 图像结束

附录

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
这些步骤其实结合代码都可以变得好懂很多!!!

特别鸣谢
同济大学cyf老师和zxh学长的教学!!!这是本人在大一时所修的一门课程作业。收获良多!

GitHub源码链接,含源码、文档(但是因为大一的代码功力不是特别好,现在也还没有多余时间调整,文档也只是作业心得口水话居多,请诸位见谅):GitHub项目源码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值