Operator Library: Compression
该算子对 8 位灰度图像执行 JPEG 压缩。它使用 JPEG 基线算法。算子的输出是一个霍夫曼流。可选地,输出中会包含 JPEG 标头(可配置)。如果包含标头,则输出格式为 1.2 版的 JFIF(JPEG 文件交换格式)。
压缩率(从而也是输出流大小)取决于两个因素:
-
在运行时可更改的所选量化表。
-
输入图像。
算子 JPEG_Encoder 能够处理链接参数化中指定的完整输入数据速率。您可以通过输入 Parallelism 来定义吞吐速率。请注意,更高的 Parallelism 会带来更高的 FPGA 资源利用率。
最大图像高度为 65,535 像素。如果图像高度不是 8 的倍数,算子会在内部添加虚拟行。这种行为会降低整体输入数据速率。
该算子允许您定义量化表。您有两种配置该表的选项:
-
可以根据 Quality 值(以百分比为单位)自动计算量化表。计算时,使用标准亮度量化表(见下文)。使用参数 Quality(以百分比为单位)来配置自动计算。自动计算是算子的默认设置。
-
或者,您可以单独设置每个量化表值。使用参数 LuminanceQuantization 输入您的值。在这种情况下,参数 Quality 会通过被设置为值 -1 而自动禁用。
标准亮度量化表(默认设置)如下所示:
在默认模式下(即根据参数 Quality 设置的标准亮度量化表进行自动计算),量化表通过以下公式计算得出:
如上所述,算子的输出是编码图像数据的霍夫曼流。对于霍夫曼编码,使用针对 DC 和 AC 系数的标准亮度表。这些表是固定的,取自文献,即 W. P. Pennbaker 和 J. L. Mitchell 所著的《JPEG Still Image Data Compression Standard》(Van Nostrand Rheinhold,1993 年)。如果参数 IncludeHeader 设置为 YES,则编码器生成的霍夫曼流包含 JPEG 标头。生成的数据流由多字节(8 位块)的并行输出组成,其中的 Parallelism 是根据吞吐量要求自动推导出来的。
算子限制
-
该算子不支持空图像,即没有像素的图像。
-
不允许输入行长度可变的图像。
-
算子具有最小输入图像宽度,该宽度取决于输入 Parallelism。最小输入图像宽度至少是输入 Parallelism 的两倍。最小输入图像宽度的计算方法如下:
-
基于输入 Parallelism:确定等于或大于输入 Parallelism 的第一个 8 的倍数。
-
将此 8 的倍数加 1。
-
基于步骤 2 的结果:由于输入图像宽度必须是输入 Parallelism 的倍数,因此确定大于步骤 2 结果的 input parallelism 的第一个倍数。
步骤 3 的结果即为算子的最小输入图像宽度。
例如,如果输入 Parallelism 为 4,则最小输入图像宽度为 12。
如果输入 Parallelism 为 12,则最小输入图像宽度为 24。
-
![]() |
优化算子吞吐量 |
|---|---|
|
如果输入 Parallelism 大于 8,则数据吞吐量取决于输入图像的大小。可以通过以下图像大小 (OptimalSize) 实现最大数据吞吐量:
在内部,该算子始终使用是 8 的倍数的 Parallelism。根据输入 Parallelism 的不同,内部 Parallelism 转换可以补偿一部分带宽损失。带宽损失仅发生在帧结束时。 |
由于压缩图像数据的大小不可预测,压缩帧的最后一个输出数据字节可能不会与输出 Parallelism 对齐。因此,一帧的最后一个数据向量可能包含随机虚拟值。为了标记帧的实际结束,将使用 JPEG 标准中定义的 EOI (End of Image) 标记。EOI 标记由两个字节组成。每帧的倒数第二个字节是 0xFF,每帧的最后一个字节是 0xD9。
为了优化图像吞吐量(带宽),算子在激活标头生成后就会立即输出标头——甚至在图像数据到达算子输入端之前。这样,标头数据的传输就不会中断图像数据的传输,因为标头是提前传输的。这种做法的缺点是,算子的输出传输开始时间早于实际图像数据传输。在特定情况下,这可能会引起混淆:
-
在 JPEG_Encoder 之后直接使用 SourceSelector 算子:Operator SourceSelector 一旦获取标头数据,就会注册部分处理的帧。因此,如果将 SourceSelector 切换为从 JPEG_Encoder 获取图像数据,则 SourceSelector 无法切换到任何其他源,因为它始终会检测到未完成的帧。此外,当启用标头生成且 SourceSelector 从其他源切换到 JPEG_Encoder 通道时,第一幅图像将丢失。
-
要测量延迟,请使用 FrameEndToSignal 算子(而不是 FrameStartToSignal 和 SignalToDelay)。
使用 InfiniteSource 进行溢出管理
在 InfiniteSource 模式下,图像可能会丢失或损坏,因为 JPEG_Encoder 模块或后续模块无法处理该带宽。如果在算子已经接受部分图像的同时发生溢出,则所有后续传入的图像数据都将被丢弃,并且算子中的截断图像将被截断,从而产生部分输出图像。如果在帧开始到达时算子处于溢出状态,则整帧都会被丢弃且该帧丢失。对于每个截断或丢失的帧,都会生成一个 VA 事件(TruncatedEvent 和 LostEvent)。 JPEG_Encoder 事件由 3 个数据包组成,每个数据包 2 个字节。前两个 VA 事件数据包构成 frame-ID,它只是到达 JPEG_Encoder 输入的每个帧的 Counter。frame-ID 用于识别丢失或截断的确切帧。第三个数据包标记发生的错误类型。Bit 0 标记帧是丢失 (Bit0 = 1) 还是截断 (Bit0 = 0)。第三个数据包的其他 15 位仅在事件丢失的情况下使用(这种情况只有在事件发生速度过快超出了 CPU 处理能力时才会发生)。第三个数据包的 Bit1 标记任何丢失的 TruncatedEvent 的发生情况,同一数据包的 Bit2 标记任何丢失的 LostEvent 的发生情况。此外,对于丢失的 LostEvents ,Bit[15:3] 组成一个 Counter,其中包含丢失的 LostEvents 的数量。如果 Counter 值为零,则丢失-LostEvent-Counter 已溢出。由于截断帧会导致 JPEG_Encoder 输出数据,而丢失帧不会,因此 VA 事件仅对丢失的 LostEvents.
| Quality | |
|---|---|
| 键入 | 静态/动态写入参数 |
| 默认 | 50.00 |
| 范围 | [1.00 - 100.00 %], {-1}, 步长 = 0.01% |
|
使用此参数可以更改 JPEG 压缩的 Quality。量化矩阵是根据上述公式从百分比值确定的。确定的量化值可以从参数 quantization_matrix 中读取。该参数是动态的,且只能在小程序空闲时进行更改。 可以定义介于 1 和 100 之间的 Quality 设置。写入此参数将覆盖通过参数 LuminanceQuantization 对量化矩阵所做的手动更改。如果从 Quality 中读取到 -1,则说明已对量化矩阵进行了手动更改。 Quality 参数是定义编码器压缩率的主要来源。亮度表将根据指定的 Quality 自动计算并可读回。不过,也可以直接修改亮度表。如果发生这种情况,Quality 参数将自动更改为 -1,以表明该参数不再有效且表使用的是手动覆盖模式。如果用户想要优化资源使用率,可以将 Quality 和量化表设置为静态模式。静态更改与动态更改只能针对 Quality 参数执行。量化表设置将自动遵循 Quality 类型,且无法手动覆盖。当 Quality 设置为 static 时,算子会根据 Quality 设置确定输出 Parallelism。在大多数情况下,与动态模式相比,输出 Parallelism 会降低,这可能意味着在牺牲运行时更改压缩率的灵活性的代价下,显著减少了 FPGA 资源。 |
|
| LuminanceQuantization | |
|---|---|
| 键入 | 遵循 Quality 类型(动态或静态)写入参数 |
| 默认 | 没有任何 |
| 范围 | [1 - 255] |
|
针对范围在 [1.00 - 100.00] 内的 Quality 自动计算,手动设置时,Quality 将失效并显示为 -1。 |
|
| IncludeHeader | |
|---|---|
| 键入 | 静态写参数 |
| 默认 | YES |
| 范围 | [YES,NO] |
|
JPEG 标头默认包含在压缩流中。但是,您可以禁用此功能。如果您将参数 IncludeHeader 设置为 NO,则 JPEG 参数 ImageHeight 和 ImageWidth 将变为未激活状态。如果您将参数 IncludeHeader 设置为 YES,则标头将被包含,并且您可以决定标头参数是应为静态还是必须为动态。如果设置为静态,则图像宽度和图像HEIGHT的值将静态嵌入标头中,并且无论输入图像大小如何都无法更改。如果设置为动态,您可以在运行时更改图像宽度和图像高度的值。请注意,这些标头参数不会自动更新为输入图像大小。如果您使用的算子,其图像大小在运行时动态变化,则您必须事后修补生成的标头。如果您将 ImageHeight 和 ImageWidth 都设置为“static”,则可以略微减少 FPGA 资源的使用量。 |
|
| ImageWidth | |
|---|---|
| 键入 | 静态/动态写入参数 |
| 默认 | 1024 |
| 范围 | 1 - 2^16-1 |
|
此参数仅在参数 IncludeHeader 设置为 YES 时可用。 参数 ImageWidth 仅用于生成如参数 IncludeHeader 中所述的 JPEG 图像标头。 |
|
| ImageHeight | |
|---|---|
| 键入 | 静态/动态写入参数 |
| 默认 | 1024 |
| 范围 | 1 - 2^16-1 |
|
此参数仅在参数 IncludeHeader 设置为 YES 时可用。 参数 ImageHeight 仅用于生成如参数 IncludeHeader 中所述的 JPEG 图像标头。 |
|
| InfiniteSource | |
|---|---|
| 键入 | 静态写参数 |
| 默认 | DISABLED |
| 范围 | {ENABLED, DISABLED} |
|
该算子可以直接插入相机算子后面。在这种情况下,必须将 InfiniteSource 参数设置为 ENABLED。然后,算子将执行主动溢出管理,并通过 VA 事件系统向软件报告溢出状况。溢出仅在两种情况下发生:算子后面的接收器停止/暂停传输,或者输入图像高度不是 8 行的倍数。在后一种情况下,算子必须填充缺少的行,以完成 JPEG 标准要求的最后一行 JPEG 块。 有关更多信息,请参见 “Infinite Sources / Connecting Cameras”。 |
|
使用以下霍夫曼 DC 和 AC 系数。
typedef char DCHuffTableType[12][17]; // Huffman table for
luminance DC coefficients DCHuffTableType Lum_DC_HuffmanTable= { "00", "010", "011", "100",
"101", "110", "1110", "11110", "111110", "1111110", "11111110", "111111110" }; typedef char
ACHuffTableType[16][11][17]; // Huffman table for luminance AC coefficients ACHuffTableType
Lum_AC_HuffmanTable= { { //Run == 0 "1010",//EOB "00", "01", "100", "1011", "11010",
"1111000", "11111000", "1111110110", "1111111110000010", "1111111110000011" }, { //Run == 1
"1010",//EOB "1100", "11011", "1111001", "111110110", "11111110110", "1111111110000100",
"1111111110000101", "1111111110000110", "1111111110000111", "1111111110001000" }, { //Run == 2
"1010",//EOB "11100", "11111001", "1111110111", "111111110100", "1111111110001001",
"1111111110001010", "1111111110001011", "1111111110001100", "1111111110001101",
"1111111110001110" }, { //Run == 3 "1010",//EOB "111010", "111110111", "111111110101",
"1111111110001111", "1111111110010000", "1111111110010001", "1111111110010010",
"1111111110010011", "1111111110010100", "1111111110010101" }, { //Run == 4 "1010",//EOB
"111011", "1111111000", "1111111110010110", "1111111110010111", "1111111110011000",
"1111111110011001", "1111111110011010", "1111111110011011", "1111111110011100",
"1111111110011101", }, { //Run == 5 "1010",//EOB "1111010", "11111110111", "1111111110011110",
"1111111110011111", "1111111110100000", "1111111110100001", "1111111110100010",
"1111111110100011", "1111111110100100", "1111111110100101" }, { //Run == 6 "1010",//EOB
"1111011", "111111110110", "1111111110100110", "1111111110100111", "1111111110101000",
"1111111110101001", "1111111110101010", "1111111110101011", "1111111110101100",
"1111111110101101" }, { //Run == 7 "1010",//EOB "11111010", "111111110111",
"1111111110101110", "1111111110101111", "1111111110110000", "1111111110110001",
"1111111110110010", "1111111110110011", "1111111110110100", "1111111110110101", }, { //Run ==
8 "1010",//EOB "111111000", "111111111000000", "1111111110110110", "1111111110110111",
"1111111110111000", "1111111110111001", "1111111110111010", "1111111110111011",
"1111111110111100", "1111111110111101" }, { //Run == 9 "1010",//EOB "111111001",
"1111111110111110", "1111111110111111", "1111111111000000", "1111111111000001",
"1111111111000010", "1111111111000011", "1111111111000100", "1111111111000101",
"1111111111000110" }, { //Run == 0xA "1010",//EOB "111111010", "1111111111000111",
"1111111111001000", "1111111111001001", "1111111111001010", "1111111111001011",
"1111111111001100", "1111111111001101", "1111111111001110", "1111111111001111" }, { //Run ==
0xB "1010",//EOB "1111111001", "1111111111010000", "1111111111010001", "1111111111010010",
"1111111111010011", "1111111111010100", "1111111111010101", "1111111111010110",
"1111111111010111", "1111111111011000" }, { //Run == 0xC "1010",//EOB "1111111010",
"1111111111011001", "1111111111011010", "1111111111011011", "1111111111011100",
"1111111111011101", "1111111111011110", "1111111111011111", "1111111111100000",
"1111111111100001" }, { //Run == 0xD "1010",//EOB "11111111000", "1111111111100010",
"1111111111100011", "1111111111100100", "1111111111100101", "1111111111100110",
"1111111111100111", "1111111111101000", "1111111111101001", "1111111111101010" }, { //Run ==
0xE "1010",//EOB "1111111111101011", "1111111111101100", "1111111111101101",
"1111111111101110", "1111111111101111", "1111111111110000", "1111111111110001",
"1111111111110010", "1111111111110011", "1111111111110100" }, { //Run == 0xF "11111111001",
//ZRL "1111111111110101", "1111111111110110", "1111111111110111", "1111111111111000",
"1111111111111001", "1111111111111010", "1111111111111011", "1111111111111100",
"1111111111111101", "1111111111111110" } }; 

![[提示]](../common/images/admon/tip.png)



上一页

