基本的JPEG压缩编码算法笔记

1. 颜色模式转换

JPEG采用的是YCrCb颜色空间,而BMP采用的是RGB颜色空间,要想对BMP图片进行压缩,首先需要进行颜色空间的转换。YCrCb颜色空间中,Y代表亮度,Cr,Cb则代表色度和饱和度。有时候U也表示Cb,V 表示Cr。RGB和YCrCb之间的转换关系如下所示:

Y = 0.299R + 0.587G + 0.114B

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

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

一般来说,C值(包括Cb Cr)应该是一个有符号的数字,但这里加上128,使其变为8位的无符号整数,从而方便数据存储和计算。

R = Y+1.402(Cr-128)

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

B = Y+1.772(Cb-128)

2. 采样

研究发现,人眼对亮度变换的敏感度要比对色彩变换的敏感度高出很多。因此,我们可以认为Y分量要比Cb,Cr分量重要。在BMP图片中,RGB三个分量各采用一个字节进行采样,也就是我们常听到的RGB888的模式;而JPEG图片中,通常采用两种采样方式:YUV411和YUV422,它们所代表的意义是Y,Cb,Cr三个分量的数据取样比例一般是4:1:1或者4:2:2(4:1:1含义就是:在2x2的单元中,本应分别有4个Y,4个U,4个V值,用12个字节进行存储。经过4:1:1采样处理后,每个单元中的值分别有4个Y、1个U、1个V,只要用6个字节就可以存储了)。这样的采样方式,虽然损失了一定的精度但也在人眼不太察觉到的范围内减小了数据的存储量。当然,JPEG格式里面也允许将每个点的U,V值都记录下来;


3. 分块

由于后面的DCT变换是对8x8的子块进行处理的,因此,在进行DCT变换之前必须把源图像进行分块。源图像中每点的3个分量是交替出现的,先把这3个分量分开,存放到3张表中去,然后由左及右,由上到下依次读取8x8的子块,存放在长度为64的表中,即可进行DCT变换。注意编码时,程序从源数据中读取一个8x8的数据块后,进行DCT变换,量化,编码,然后再读取,处理下一个8x8的数据块。JPEG编码是以每8x8个点为一个单位进行处理的,所以如果原始图片的长宽不是8的倍数,都需要先补成8的倍数,使其可以进行一块块的处理。将原始图像数据分为8x8的数据单元矩阵之后,还必须将每个数值减去128,然后一一带入DCT变换公式,即可达到DCT变换的目的。图像的数值减去128,是因为DCT所接受的数字范围是-128~127之间 。

4.离散余弦变换

DCT是码率压缩中常用的一种变换编码方法。任何连续的实对称函数的傅里叶变换中只含有余弦项,因此,余弦变换同傅里叶变换一样具有明确的物理意义。DCT是先将整体图像分成N*N的像素块,然后针对N*N的像素块逐一进行DCT操作。需要提醒的是,JPEG的编码过程需要进行正向离散余弦变换,而解码过程则需要反向离散余弦变换。

N是水平垂直的像素数目,一般取值为8,8*8的二维像素块经过DCT操作之后,就得到了8*8的变换系数矩阵。这些系数,都有具体的物理含义,例如,U=0,V=0时的F(0,0)是原来的64个数据的均值,相当于直流分量,也有人称之为DC系数或者直流系数。随着U,V的增加,另外的63个系数则代表了水平空间频率和垂直空间频率分量的大小,多半是一些接近于0的正负浮点数,我们称之为交流系数AC。DCT变换后的8*8系数矩阵中,低频分量集中在矩阵的左上角,高频成分集中在右下角。

由于大多数图像的高频分量比较小,相应的图像高频分量的DCT系数经常接近于0,再加上高频分量中只包含了图像的细微的细节变化信息,而人眼对这种高频成分的失真不太敏感,所以,可以考虑将这一些高频成分予以抛弃,从而降低需要传输的数据量。这样一来,传送DCT变换系数的所需要的编码长度要远远小于传送图像像素的编码长度。到达接收端之后通过反离散余弦变换就可以得到原来的数据,虽然这么做存在一定的失真,但人眼是可接受的,而且对这种微小的变换是不敏感的。
5.Zigzag扫描

DCT讲一个8*8的数组变换成另一个8*8的数组,但是内存里面所有数据都是线性存放的,保存和读取顺序按照下图

可见是按照Z字形或者之字形来的

6.量化

图像数据转换为DCT频率系数之后,还要进行量化阶段,才能进入编码过程。量化阶段需要两个8*8量化矩阵数据,一个是专门处理亮度的频率系数,另一个则是针对色度的频率系数,将频率系数除以量化矩阵的值之后取整,即完成了量化过程。当频率系数经过量化之后,将频率系数由浮点数转变为整数,这才便于执行最后的编码。不难发现,经过量化阶段之后,所有的数据只保留了整数近似值,也就再度损失了一些数据内容。在JPEG算法中,由于对亮度和色度的精度要求不同,分别对亮度和色度采用不同的量化表。前者细量化,后者粗量化。

7. DC系数的差分脉冲调制编码

8*8的图像块经过变换之后得到的DC系数有两个特点:系数的数值比较大;相邻的8*8图像块的DC系数值变换不大;根据这两个特点,DC系数一般采用差分脉冲调制编码DPCM(Difference Pluse Code Modulation),即:取同一个图像分量中每个DC值与前一个DC值的差值来进行编码。对差值进行编码所需要的位数会比对原值进行编码所需要的位数少了很多。假设某一个8*8图像块的DC系数值为15,而上一个8*8图像块的DC系数为12,则两者之间的差值为3。

8. DC系数的中间格式计算

 JPEG中为了更进一步节约空间,并不直接保存数据的具体数值,而是将数据按照位数分为16组,保存在表里面。这也就是所谓的变长整数编码VLI。即,第0组中保存的编码位数为0,其编码所代表的数字为0;第1组中保存的编码位数为1,编码所代表的数字为-1或者1......,如下面的表格所示,这里,暂且称其为VLI编码表:

前面提到的那个DC差值为3的数据,通过查找VLI可以发现,整数3位于VLI表格的第2组,因此,可以写成(2)(3)的形式,该形式,称之为DC系数的中间格式。

9. AC系数的行程长度编码(RLC)

量化之后的AC系数的特点是,63个系数中含有很多值为0的系数。因此,可以采用行程编码RLC(Run Length Coding)来更进一步降低数据的传输量。

10. AC系数的中间格式

Huffman编码:对出现概率大的字符分配字符长度较短的二进制编码,对出现概率小的字符分配字符长度较长的二进制编码,从而使得字符的平均编码长度最短。Huffman编码的原理请参考数据结构中的Huffman树或者最优二叉树。

11. 简单举例说明

Before computing the DCT of the 8×8 block, its values are shifted from a positive range to one centered on zero. For an 8-bit image, each entry in the original block falls in the range {\displaystyle [0,255]}. The midpoint of the range (in this case, the value 128) is subtracted from each entry to produce a data range that is centered on zero, so that the modified range is {\displaystyle [-128,127]}. This step reduces the dynamic range requirements in the DCT processing stage that follows.

 

<think>好的,我现在要解决用户遇到的关于执行 `sudo apt update` 时出现的GPG签名错误问题。错误信息显示缺少公钥`ED444FF07D8D0BF6`,导致无法验证Kali仓库的签名,进而无法安全更新。首先,我需要回忆一下常见的解决方法,并确保步骤正确且适合用户的情况。 首先,用户使用的是Kali Linux的仓库,但系统提示公钥不可用。通常,这种情况发生在系统没有存储库的GPG密钥时。APT包管理器依赖这些密钥来验证软件包的合法性,确保它们没有被篡改。所以,缺少公钥会导致更新被阻止。 接下来,我需要考虑如何导入正确的公钥。用户遇到的错误中提到的公钥ID是`ED444FF07D8D0BF6`。通常,解决这类问题的方法是使用`apt-key`命令手动添加密钥,或者使用`wget`下载密钥并通过`apt-key add`导入。不过,需要注意`apt-key`在较新版本的Debian/Ubuntu中已被弃用,但Kali基于Debian,可能仍然支持这种方式。 另一个可能的步骤是检查仓库源的配置是否正确。用户当前的仓库地址是`http://kali.download/kali`,可能需要确认这是否是官方推荐的源。有时候,仓库URL的变化或拼写错误也会导致问题,但错误信息中的`NO_PUBKEY`更可能直接指向密钥问题。 然后,具体的解决方法应该是导入缺失的公钥。根据经验,可以使用以下命令: ``` sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ED444FF07D8D0BF6 ``` 这里,`--keyserver`指定了密钥服务器,通常使用Ubuntu的服务器,因为Kali可能与Debian/Ubuntu共享部分资源。执行这个命令后,系统会从指定的服务器获取并导入公钥。 如果上述方法失败,可能需要尝试其他密钥服务器,比如`hkp://keys.gnupg.net`或者`pgp.mit.edu`。有时不同的服务器响应情况不同,换一个服务器可能解决问题。 另外,也可以直接下载密钥文件并手动添加。例如,使用`wget`下载,然后导入: ``` wget -q -O - https://archive.kali.org/archive-key.asc | sudo apt-key add - ``` 但需要确认这个URL是否确实提供正确的密钥。Kali的官方文档可能有相关说明,用户应参考官方指南确保来源可靠。 导入密钥后,再次运行`sudo apt update`应该可以解决问题。如果仍然失败,可能需要检查网络连接,确保能够访问密钥服务器,或者暂时使用HTTP而非HTTPS的仓库源(不过安全性较低,不推荐长期使用)。 另外,用户可能需要更新系统上已有的密钥环包,例如安装`kali-archive-keyring`包。这个包通常包含了Kali仓库所需的信任密钥,安装后可以自动解决此类问题。命令可能如下: ``` sudo apt install kali-archive-keyring ``` 但执行这个命令前,可能需要先处理当前无法更新的问题,形成一个“先有鸡还是先有蛋”的情况。如果系统完全无法更新,可能需要手动下载该包的.deb文件并安装,或者从其他渠道获取。 最后,如果所有方法都无效,用户应检查是否使用的是正确的仓库地址,并参考Kali Linux的官方文档或社区支持,以获取最新的解决方法。确保步骤的安全性,避免添加不受信任的源或密钥,以防止潜在的安全风险。</think>以下是对该问题的分步解释及解决方案: **错误原因分析:** 1. 系统缺少Kali软件仓库的GPG公钥(`ED444FF07D8D0BF6`) 2. APT包管理器无法验证软件包签名,出于安全考虑禁止更新 **解决方法:** 1. **手动导入缺失的GPG公钥** ```bash sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys ED444FF07D8D0BF6 ``` *说明*:从Ubuntu密钥服务器获取指定公钥 2. **更新软件源(再次尝试)** ```bash sudo apt update ``` **备选方案(若上述方法失败):** 1. **使用不同密钥服务器** ```bash sudo apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys ED444FF07D8D0BF6 ``` 2. **直接安装Kali密钥环包** ```bash sudo apt install -y kali-archive-keyring ``` **验证修复:** ```bash sudo apt update && sudo apt upgrade -y ``` 应不再出现`NO_PUBKEY`错误提示 **注意事项:** 1. Kali Rolling仓库地址建议使用官方推荐地址: ```bash deb http://http.kali.org/kali kali-rolling main contrib non-free ``` 2. 确保系统时间准确(时区错误可能导致GPG验证失败) 3. 如使用代理,请确保密钥服务器可达 **原理说明:** APT使用GPG签名验证软件包的真实性,每个官方仓库都会提供对应的公钥。当本地系统缺少对应公钥时,就会触发安全保护机制阻止更新。通过手动添加公钥,即可重建信任链完成验证。 如果问题仍未解决,建议检查: 1. `/etc/apt/sources.list`文件内容 2. 网络连接状态 3. 系统时间准确性 4. 防火墙/安全组设置是否阻挡密钥服务器访问
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值