C# MPEG1 图像压缩类






4.73/5 (21投票s)
2004年1月13日
6分钟阅读

247044

7685
本文展示了如何使用 MPEG1 格式压缩图像
引言
C# 在图像转换和压缩方面有大量支持,但我从未找到一个好的工具可以将图像转换为 MPEG 格式。我希望有人能为我做这件事,但既然没有人做,我就编写了一个名为 MPEGFunctions
的类,它提供了将位图图像转换为 MPEG1 I 帧所需的功能。代码是可用的,但绝对没有经过优化或高效。我认为 MPEGFunctions
类和提供的示例应用程序是一个很好的学习工具,如果您想了解更多关于 MPEG 图像压缩的知识。
我需要这样一个程序有几个原因。第一个是我的一些 MPEG 动画在我的网站上,我希望在视频剪辑的开头放一个简短的标题屏幕。我可以使用类似 Microsoft Paint 的工具创建一个标题屏幕,将其转换为持续 2 秒的 MPEG 序列,然后用 Windows Media Player 播放(Media Player 不会显示 JPEG,但会显示我的 MPEG 序列)。另一个原因是我的工作涉及数字机顶盒,我需要一种方法来创建机顶盒可以显示的 MPEG 静止帧。机顶盒擅长渲染 MPEG,但通常无法显示 JPEG。
背景
MPEG1 标准(ISO/IEC 11172 Part 2)描述了将图像编码和压缩为 MPEG1 格式的过程。我在网上找到的一个很好的教程链接,对我帮助很大,可以在这里找到
或者在 Google 上搜索:jpeg dct cmpt365。
MPEGFunctions
类的源代码在名为 Class1.cs 的文件中。ImageFunctions
类的源代码在 ImageFunctions.cs 文件中。
最简单的 MPEG 帧类型是 I 帧。要将图像转换为 MPEG I 帧,您需要从 RGB 位图开始,然后执行以下步骤:
- 在高度和宽度维度上填充位图,使位图尺寸成为 16 的偶数倍。您需要这样做,因为 MPEG 图像的基本构建块是 16x16 像素的宏块。使用
ImageFunctions.padWidth
和ImageFunctions.padHeight
函数。 - 将图像分解为 16x16 像素的宏块。
- 对于每个宏块,创建 4 个 8x8 像素的 Y 块,并对宏块进行子采样以创建 1 个 8x8 像素的 CR 块和 1 个 8x8 像素的
CBblock
。将像素的 RGB 值转换为 Y、CR 和 CB 颜色分量。使用MPEGFunctions.getYMatrix
、MPEGFunctions.getCRMatrix
和MPEGFunctions.getCBMatrix
函数。 - 为每个块计算离散余弦变换 (DCT)。使用
MPEGFunctions.calculateDCT
函数。 - 对 DCT 系数进行量化。使用
MPEGFunctions.Quantize
函数。 - 使用锯齿扫描重新排列每个块的 DCT 系数。使用
MPEGFunctions.Zigzag
函数。 - 为 DC DCT 系数计算霍夫曼编码序列。使用
MPEGFunctions.DCHuffmanEncode
函数。 - 为 AC DCT 系数计算霍夫曼编码序列。使用
MPEGFunctions.ACHuffmanEncode
函数。 - 对图像中的每个宏块重复步骤 3 到 8。
- 将 MPEG 头部、霍夫曼编码和 MPEG 尾部写入内存流、文件或其他输出格式。
使用代码
示例应用程序演示了如何使用 MPEGFunctions
类。
- 使用 File->Open 选择任何 C# 支持的图像格式(GIF、JPEG、BMP 等)。图像将被放入 pictureBox1。如果图像小于 352x352 像素,它将以其正常大小显示。如果更大,它将被拉伸/压缩以适应 352x352 的 picture box。如果需要,图像将被填充以使尺寸能被 16 整除。
- 如果选择 WriteToFile->MPEG IFrame,图像将被转换为 MPEG1 IFrame 并写入选定的输出文件。您可以使用 Windows Media Player 打开输出文件,它将显示出来。
- 如果选择 WriteToFile->MPEG Sequence,图像将被转换为 IFrame。转换后的图像将根据对话框中选择的帧数重复。整个序列将被写入选定的输出文件。您可以使用 Windows Media Player 打开输出文件,它将以每秒 30 帧的速度播放。
- 如果您单击 pictureBox1 中的某个位置,关联的 16x16 像素宏块将在 pictureBox2 中显示。宏块将被拉伸以适应 pictureBox2 的尺寸。
- 如果您选择“Block Details”按钮,您将进入一个新的对话框,在那里您可以查看宏块的 R、G 和 B 像素值。
- 如果您选择“Convert To YPrPb”按钮,您将进入一个新的对话框,在那里您可以查看宏块的 Y、Pr 和 Pb 值。
- 如果您选择“Calculate DCT”按钮,您将进入一个新的对话框,在那里将显示选定块的 DCT 变换值。
- 如果您选择“Quantize”按钮,您可以看到量化步骤的结果。
- 如果您选择“ZigZag Order”按钮,您可以看到重新排序 DCT 系数的结果。
- 如果您选择“DC Encode”,您可以看到霍夫曼编码 DC 值生成的二进制字符串。
- 如果您选择“AC Encode”,您可以看到霍夫曼编码 AC 值生成的二进制字符串。
关注点
MPEG I 帧与 JPEG 图像非常相似,事实上,创建 JPEG 的过程与 MPEG 几乎相同。最终比特流的语法不同,但通过一些简单的更改,您可以将 MPEGFunctions
类转换为 JPEGFunctions
类。然而,在 C# 中,将图像保存为 JPEG 非常简单,以至于实际上没有必要。您可以在我的示例应用程序的 UserControl1.WriteJPEG
函数中看到将位图转换为 JPEG 有多简单。
MPEG 实际上并不是为单个图像压缩设计的。它实际上是用于视频压缩的,它的很多有用性来自于使用先前和未来的视频帧来预测任何单个视频帧的样子。这些被称为 P 帧和 B 帧,可以比仅使用 I 帧更有效地压缩视频。
结论
到目前为止,我只能处理 MPEG I 帧,但我希望继续这个项目,并添加创建 MPEG P 帧和 B 帧所需的功能。我将来还会创建一个类似于 MPEGFunctions
类的 JPEGFunctions
类。希望大约 3 个月后,这个项目会有更新。