Operator JPEG_Encoder

Operator Library: Compression

此 Operator 會對 8 位元灰階影像執行 JPEG 壓縮。它使用 JPEG 基線演算法。此 Operator 的輸出為 Huffman 資料流。選用性地,輸出中會包含 JPEG 標頭(可進行參數化)。如果包含標頭,則輸出格式為 JFIF(JPEG 檔案交換格式)1.2 版。

壓縮率(以及因此產生的輸出資料流大小)取決於兩個因素:

  • 執行階段可變更的所選量化表。

  • 輸入影像。

Operator JPEG_Encoder 能夠處理鏈結參數化中所指定的完整輸入資料速率。您可以透過輸入 Parallelism 定義吞吐率。請注意,較高的 Parallelism 會導致較高的 FPGA 資源使用率。

最大影像高度為 65,535 個像素。如果影像高度不是 8 的倍數,Operator 會在內部新增虛擬行。此行為會降低整體輸入資料速率。

此 Operator 允許您定義量化表。您有兩種選項可設定此表格:

  • 量化表可以根據 Quality 值(以百分比表示)自動計算。計算時會使用標準明亮度量化表(見下方)。使用參數 Quality(以百分比表示)來設定自動計算。自動計算是此 Operator 的預設設定。

  • 或者,您也可以個別設定每個量化表值。使用參數 LuminanceQuantization 輸入您的值。在這種情況下,參數 Quality 會透過設為值 -1 而自動停用。

標準明亮度量化表(預設設定)如下所示:

在預設模式下(即由參數 Quality 從標準明亮度量化表中進行自動計算),量化表透過以下公式計算:

如上所述,此 Operator 的輸出是編碼影像資料的 Huffman 資料流。對於 Huffman 編碼,會使用 DC 和 AC 係數的標準明亮度表格。這些表格是固定的且取自文獻,即 W. P. Pennbaker 和 J. L. Mitchell 所著的《JPEG Still Image Data Compression Standard》(Van Nostrand Rheinhold,1993 年)。如果參數 IncludeHeader 設為 YES,則編碼器產生的 Huffman 資料流會包含 JPEG 標頭。產生的資料流由多個位元組(8 位元區塊)的平行輸出組成,其中 Parallelism 是根據吞吐量需求自動推導出來的。

算子限制

  • 此 Operator 不支援空白影像,也就是沒有像素的影像。

  • 不允許具有不同行長度的輸入影像。

  • 此 Operator 具有最小輸入影像寬度,該寬度取決於輸入 Parallelism。最小輸入影像寬度至少為輸入 Parallelism 的兩倍。最小輸入影像寬度的計算方式如下:

    1. 根據輸入 Parallelism:識別第一個大於或等於輸入 Parallelism 的 8 的倍數。

    2. 在此 8 的倍數中加上值 1。

    3. 根據步驟 2 的結果:由於輸入影像寬度必須是輸入 Parallelism 的倍數,因此識別第一個大於步驟 2 結果的 輸入 Parallelism 的倍數。

    步驟 3 的結果即為此 Operator 的最小輸入影像寬度。

    計算最小輸入影像寬度的公式

    圖 414:計算最小輸入影像寬度的公式


    例如,如果輸入 Parallelism 為 4,則最小輸入影像寬度為 12。

    如果輸入 Parallelism 為 12,則最小輸入影像寬度為 24。

[提示] 最佳化 Operator 輸送量

如果輸入 Parallelism 大於 8,資料輸送量將取決於輸入影像的大小。 最大資料輸送量可透過以下影像大小 (OptimalSize) 達到:

OptimalSize = Ceil(FrameSize/(PathCount * IntervalSize))*PathCount * IntervalSize

FrameSize = ceil(ImageWidth/8)*8 * ceil(ImageHeight/8)*8;

PathCount = ceil(Par/8)

IntervalSize:大於 7 且與 PathCount 沒有共同因數的下一個值。

在內部,Operator 總是使用 8 的倍數作為 Parallelism。根據輸入 Parallelism,內部 Parallelism 轉換可以補償部分頻寬損失。 頻寬損失僅發生在畫格結尾。

由於壓縮影像資料的大小無法 預測,壓縮畫格的最後一個輸出資料位元組可能無法對齊 輸出 Parallelism。因此,畫格的最後一個資料向量可能包含隨機虛擬 值。為了標記畫格的實際結尾,將使用 JPEG 標準中定義的 EOI (End of Image) 標記。 EOI 標記由兩個位元組組成。每個畫格的倒數第二個位元組是 0xFF, 且每個畫格的最後一個位元組是 0xD9。

為了最佳化其影像輸送速率 (頻寬),Operator 一旦啟用標頭產生功能,就會輸出標頭 ——甚至在影像資料到達 Operator 的 輸入端之前。這樣一來,標頭資料的傳輸就不會中斷影像資料的傳輸, 因為標頭是提前傳輸的。這種做法的缺點是 Operator 的輸出傳輸開始時間早於實際的影像資料傳輸。 在特定情況下,這可能會引起混淆:

  • 在 JPEG_Encoder 之後直接使用 SourceSelector Operator: Operator SourceSelector 會在取得標頭資料時立即註冊部分處理的畫格。因此,如果 SourceSelector 切換為從 JPEG_Encoder 取得影像資料,SourceSelector 將無法切換到任何其他來源,因為它總是偵測到未完成的畫格。 此外,當啟用標頭產生功能且 SourceSelector 從其他 來源切換到 JPEG_Encoder 通道時,第一張影像將會遺失。

  • 若要測量延遲,請使用 FrameEndToSignal Operator (而不是 FrameStartToSignal 和 SignalToDelay)。

使用 InfiniteSource 進行溢位管理

在 InfiniteSource 模式下,影像可能會 遺失或損壞,因為 JPEG_Encoder 模組或後續模組之一 無法處理該頻寬。如果在 Operator 已經 接受部分影像時發生溢位,則所有後續的輸入影像資料都將被捨棄,並且 Operator 中的截斷 影像將被截斷,從而產生部分輸出影像。如果 Operator 在畫格開始到達時處於溢位狀態,則整個畫格將被捨棄 且畫格遺失。對於每個截斷或遺失的畫格,都會產生一個 VA 事件 (TruncatedEvent 和 LostEvent)。這些 JPEG_Encoder 事件由 3 個封包組成,每個封包 2 個 位元組。前兩個 VA 事件封包組成 Frame-ID,它只是到達 JPEG_Encoder 輸入端的每個畫格的 Counter 。Frame-ID 可精確識別 遺失或截斷的畫格。第三個封包標記發生的錯誤類型。 Bit 0 標記畫格是遺失 (Bit0 = 1) 還是截斷 (Bit0 = 0)。第三個封包的 其他 15 個 bit 僅在事件遺失的情況下使用,這只有在事件對於 CPU 而言發生得太快時才會發生。 第三個封包的 Bit1 標記任何 TruncatedEvent 遺失的情況, 而同一封包的 Bit2 標記任何 LostEvent 遺失的情況。 此外,對於 LostEvents 遺失的情況, Bit[15:3] 形成一個 Counter,用於保存 LostEvents 遺失的數量。 如果 Counter 值為零,則遺失 -LostEvent-Counter 已溢位。由於截斷的畫格會產生 JPEG_Encoder 輸出資料,但遺失的畫格 不會,因此 VA 事件僅計算遺失的 LostEvents.

Overflow Event Data

圖 415. 溢位事件資料


I/O Properties

Property Value
Operator Type M
Input Link I, data input
Output Link O, data output

支援的 Link 格式

Link Parameter Input Link I Output Link O
Bit Width 8 8
Arithmetic unsigned as I
Parallelism any 自動計算
Kernel Columns 1 as I
Kernel Rows 1 as I
Img Protocol VALT_IMAGE2D as I
Color Format VAF_GRAY as I
Color Flavor FL_NONE as I
Max. Img Width 2^16 -1 = 65,5351 any2
Max. Img Height 2^16 -1 = 65,535 1

1

此數值不得低於最小影像寬度要求。

2

輸出連結處的影像寬度是可配置的。如果輸出影像大於為輸出連結配置的最大影像寬度,則影像將被截斷,並丟棄剩餘的影像資料。每個影像的最後兩個位元組始終包含影像結束標記 (EOI)。

參數

Quality
Type static/dynamic write parameter
Default 50.00
Range [1.00 - 100.00 %], {-1}, 步進值 = 0.01%

使用此參數可以變更 JPEG 壓縮的 Quality。量化矩陣是根據上述方程式從百分比數值決定的。所決定的量化數值可以從參數 quantization_matrix 讀取。此參數是動態的,且應僅在 applet 閒置期間變更。

可以定義介於 1 到 100 之間的 Quality 設定。寫入此參數會覆寫透過參數 LuminanceQuantization 對量化矩陣進行的手動變更。如果從 Quality 讀取到 -1,則表示已手動變更量化矩陣。

Quality 參數是用於定義編碼器壓縮率的主要來源。亮度表將根據指定的 Quality 自動計算並可回讀。不過,也可以直接修改亮度表。如果發生這種情況,Quality 參數將自動變更為 -1,以顯示該參數已失效,並且正使用表格的手動覆寫模式。如果使用者想要最佳化資源使用率,可以將 Quality 和量化表格設定為靜態模式。靜態與動態變更只能針對 Quality 參數執行。量化表格設定將自動遵循 Quality 類型,且無法手動覆寫。當 Quality 設定為靜態時,運算子會從 Quality 設定決定輸出 Parallelism。在大多數情況下,相較於動態模式,輸出 Parallelism 將會減少,這意味著可以大幅減少 FPGA 資源,但代價是放棄在執行階段變更壓縮率的靈活性。

LuminanceQuantization
Type 遵循 Quality 類型(動態或靜態)寫入參數
Default 無
Range [1 - 255]

針對 [1.00 - 100.00] 範圍內的 Quality 自動計算;當手動設定時,Quality 會失效並設為 -1。

IncludeHeader
Type 靜態寫入參數
Default YES
Range [YES,NO]

依預設,JPEG 標頭會包含在壓縮串流中。不過,您可以停用此功能。如果您將參數 IncludeHeader 設定為 NO,則 JPEG 參數 ImageHeight 和 ImageWidth 將會停用。如果您將參數 IncludeHeader 設定為 YES,則會包含標頭,並且您可以決定標頭參數是要設為靜態還是必須為動態。如果設定為靜態,影像寬度和影像高度的數值將會靜態嵌入標頭中且無法變更,無論輸入影像大小為何。如果設定為動態,您可以在執行階段變更影像寬度和影像高度的數值。請注意,這些標頭參數不會自動更新為輸入影像大小。如果您使用的運算子其影像大小在執行階段會動態變更,則您必須事後修補產生的標頭。如果您將 ImageHeight 和 ImageWidth 都設定為 "static",則可以微幅降低 FPGA 資源的使用量。

ImageWidth
Type static/dynamic write parameter
Default 1024
Range 1 - 2^16-1

此參數僅在參數 IncludeHeader 設定為 YES 時可用。

參數 ImageWidth 僅用於產生如參數 IncludeHeader 中所述的 JPEG 影像標頭。

ImageHeight
Type static/dynamic write parameter
Default 1024
Range 1 - 2^16-1

此參數僅在參數 IncludeHeader 設定為 YES 時可用。

參數 ImageHeight 僅用於產生如參數 IncludeHeader 中所述的 JPEG 影像標頭。

InfiniteSource
Type 靜態寫入參數
Default DISABLED
Range {ENABLED, DISABLED}

此運算子可以直接插入相機運算子之後。在這種情況下,InfiniteSource 參數必須設定為 ENABLED。然後,運算子將執行主動溢位管理,並透過 VA 事件系統向軟體回報溢位狀況。溢位僅會在 2 種情況下發生:運算子後方的接收端停止/暫停傳輸,或者輸入影像高度不是 8 行的倍數。在後一種情況下,運算子必須填補缺少的行,以完成 JPEG 標準要求的最後一列 JPEG 區塊。

請參閱 'Infinite Sources / Connecting Cameras' 以取得更多資訊。

使用範例

以下範例顯示了 JPEG_Encoder 運算子的使用方式:

更多資訊

使用了以下霍夫曼 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" } };