手动实现了从图像像素值编码到JPEG格式的过程,未调用任何windowsAPI
![[Pasted image 20241110004814.png]]
注意本代码由于已经编码成了jpeg文件,只需要lena.dat修改为lena.jpeg的格式即可
- 输入:图像文件(如PNG或BMP)。
- 输出:图像的像素值矩阵(RGB)。
-
操作:将RGB颜色空间转换为YCbCr。
-
公式: $$ Y = 0.299 \times R + 0.587 \times G + 0.114 \times B $$ $$
Cb = 128 - 0.168736 \times R - 0.331364 \times G + 0.5 \times B $$ $$ Cr = 128 + 0.5 \times R - 0.5 \times G - 0.081312 \times B $$
- 操作:将YCbCr图像分为8x8的块。
- 算法:遍历图像,提取每个8x8的子矩阵。
- 操作:对每个8x8的块应用DCT。
- 公式:
$$
DCT(u,v) = \frac{1}{4} \sum_{x=0}^{7} \sum_{y=0}^{7} f(x,y) \cos \left( \frac{(2x+1)u\pi}{16} \right) \cos \left( \frac{(2y+1)v\pi}{16} \right)
$$
- 其中 (f(x,y)) 是8x8块的像素值。
-
操作:将DCT系数进行量化,使用量化表。
-
算法:逐个DCT系数与量化表对应的元素相除并四舍五入。
-
量化表示例(常用的Y和Cb/Cr量化表):
Y 量化表: $$ \begin{bmatrix} 16 & 11 & 10 & 16 & 24 & 40 & 51 & 61 \ 12 & 12 & 14 & 19 & 26 & 58 & 60 & 55 \ 14 & 13 & 16 & 24 & 40 & 57 & 69 & 56 \ 14 & 17 & 22 & 29 & 51 & 87 & 80 & 62 \ 18 & 22 & 37 & 56 & 68 & 109 & 103 & 77 \ 24 & 35 & 55 & 64 & 81 & 104 & 113 & 92 \ 49 & 64 & 78 & 87 & 103 & 121 & 120 & 101 \ 72 & 92 & 95 & 98 & 112 & 100 & 103 & 99 \end{bmatrix} $$
Cb/Cr 量化表: $$
\begin{bmatrix} 17 & 18 & 24 & 47 & 99 & 99 & 99 & 99 \ 18 & 21 & 26 & 66 & 99 & 99 & 99 & 99 \ 24 & 26 & 56 & 99 & 99 & 99 & 99 & 99 \ 47 & 66 & 99 & 99 & 99 & 99 & 99 & 99 \ 99 & 99 & 99 & 99 & 99 & 99 & 99 & 99 \ 99 & 99 & 99 & 99 & 99 & 99 & 99 & 99 \ 99 & 99 & 99 & 99 & 99 & 99 & 99 & 99 \ 99 & 99 & 99 & 99 & 99 & 99 & 99 & 99 \end{bmatrix}
$$
- 操作:对量化后的DCT系数进行Zigzag扫描,以便将高频成
- 集到后面。
- 算法:按照Zigzag顺序遍历8x8的DCT系数,将结果放入一维数组。
- 操作:使用哈夫曼编码对Zigzag扫描结果进行编码。
- 算法:
- 计算每个值的出现频率。
- 构建哈夫曼树。
- 生成哈夫曼编码表。
- 使用哈夫曼编码替换Zigzag数组中的值。
![[Pasted image 20241023192426.png]]
- 操作:将头部信息和编码后的数据写入JPEG文件。
- 步骤:
- 写入SOI(Start of Image)标记。
- 写入APP0标记和图像的宽度、高度、色彩空间等信息。
- 写入量化表和哈夫曼表。
- 写入压缩后的图像数据。
- 写入EOI(End of Image)标记。
- 输出:生成的JPEG文件。
- 实际实现时,需要处理边界条件,如图像大小不是8的倍数的情,本代码使用了边缘像素替代扩展的像素
- 对于Huffman编码,需要构建和使用相应的表,本代码离线了这样过程,采用了标准编码表
- 在具体的编码过程中有许多细微的小细节,个人认为是比压缩过程更为繁琐的部分