4

我正在编写一个 C++ 程序来将 BMP 图像转换为 JPEG。

这是我试图遵循的基本算法:

  1. 将 RGB 颜色空间转换为 Y,Cb,Cr..
  2. 将 Cb 和 Cr 向下采样 2(这意味着对于 2*2 的每个方形块有 4 个不同的 Y 值,但 1 个 Cb 和 1 个 Cr 值
  3. 将 DCT 应用于每个 8*8 像素的数据单元...
  4. 然后使用标准的 Cb 和 Cr 量化表对 DCT 系数进行量化。
  5. 做之字形排序。
  6. 使用霍夫曼编码分别对直流和交流系数进行编码。
  7. 写入正确的标头并将霍夫曼编码值写入文件...

我已经验证我正确地执行了上述操作,但我仍然遇到以下问题:

  • 生成的 JPEG 未正确显示。
  • 我制作了一个小的 8*8 24 位(颜色深度)bmp 文件,完全填充了颜色值 R=10 B=10 和 G=100...所有 64 个像素都是相同的颜色..
  • 我在每一步得到的数据如下......
    • BMP 标头大小为 40
    • 标头大小 40
    • 宽度 8
    • 身高 8
    • 飞机数量 1
    • 每像素位数 24
    • 图像尺寸 194
    • x 分辨率每米像素 2834
    • y 分辨率每米像素 2834
    • 颜色数 0
    • 小鬼颜色数 0
    • (R,B,G)=(10,10,100)的Y Cb Cr换算为(62,-29,-37)

所以让我们首先考虑 Y 分量。

Y 分量的 DCT 系数为:

 495 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0

在量化之后,对于 Y 分量,我得到的单个数据单元的锯齿形排序是这样的。

30 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0

现在上述之字形顺序数组的霍夫曼编码为:

  • Y直流编码:00111110
  • Y ac 编码:1010(对于 ac 霍夫曼表(亮度 Y)EOB 值为 1010)
  • Cb和Cr分量的类似哈夫曼编码如下:
  • cb直流编码:11000010
  • cb ac 编码:01(对于 ac 霍夫曼表(色度 Cb,Cr)EOB 值为 01)
  • cr直流编码:110101110
  • cr 交流编码:01
  • 我得到的最终霍夫曼代码是:

    001111101010110000100111010111001 长度33

所以为了使它能被8整除,填充1就完成了。

0011111010101100001001110101110011111111 Length 40.

这里每个 0 或 1 实际上是一个位,需要按原样存储在 JPEG 文件中,但由于我们不能逐位写入文件,因此总共取 8 位并转换为基数中的整数值10 并存储到一个 1 字节的字符中。

任何人都可以就我哪里出错提供任何建议吗?

4

2 回答 2

2

解决您的问题的第一件事是获取有关 JPEG 标准的 Pennebaker/Mitchel 书籍。

操作顺序为:

1) 色彩空间转换 2) FDCT 3) 量化 4) 之字形重新排序 5) 霍夫曼编码

由于您必须遵循许多规则,因此这些操作具有许多复杂性。

a) 您是否正确处理 DC 预测器?b)您是否正确编码了 A/C 组件?c)您是否尊重有关“填充零”和标记的输出流规则?d) 您的色彩空间转换公式是否正确?它是否包括必须从每个组件中减去的 0x80?e) 您是否根据您选择的二次采样选项以正确的顺序对 MCU 模块进行编码?

于 2009-07-19T21:27:06.767 回答
-2

不要重新发明轮子。使用 ImageMagick、Magick++ 或 CImg 来完成此操作。

于 2009-07-19T22:20:01.810 回答