Operator JPEG_Encoder

運算子函式庫:壓縮

此運算子對 8 位元灰階影像執行 JPEG 壓縮。它採用 JPEG 基準演算法。此運算子的輸出為 霍夫曼(Huffman)串流。可選擇性地在輸出中包含 JPEG 標頭(可設定參數)。若 包含標頭,則輸出格式為 JFIF(JPEG 檔案交換格式),版本 1.2。

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

  • 在所選的量化表上,該量化表可在執行期間進行變更。

  • 在輸入影像上。

運算子JPEG_Encoder能夠 處理連結參數化中指定的完整輸入資料速率。您可以 透過輸入並行度來定義吞吐量。請注意,較高的並行度 會導致 FPGA 資源利用率提高。

影像的最大高度為 65.535 像素。若 影像高度並非 8 的倍數,運算子會在內部插入虛線。此 行為會降低整體輸入資料傳輸速率。

此運算子可讓您定義量化 表。您有兩種方式可設定該表:

  • 量化表可根據品質值 (以百分比表示)自動計算。計算時,將採用標準亮度量化表(參見下文) 。請使用參數 Quality (以百分比為單位)來設定 自動計算功能。自動計算是該 運算子的預設設定。

  • 此外,您也可以個別設定每個量化表的數值。請使用 參數LuminanceQuantization來輸入您的數值。 此參數 Quality 將在此情況下 自動停用,並被設定為值 -1。

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

在預設模式下(即根據 由參數設定的標準亮度量化表進行自動計算 Quality所設定的標準亮度量化表進行自動計算), 量化表是根據以下方程式計算得出的:

如上所述,此運算子的輸出為 經編碼之影像資料的霍夫曼資料流。霍夫曼編碼採用標準的亮度表 ,適用於DC 及AC係數。這些表為固定值,取自文獻,即 W. P. Pennbaker 與 J. L. Mitchell 所著的《JPEG 靜態影像資料壓縮標準》(JPEG Still Image Data Compression Standard),Van Nostrand Rheinhold 出版社,1993年。 若參數IncludeHeader設定為 YES,則由編碼器產生的 霍夫曼資料流將包含 JPEG 標頭。生成的資料流由多個位元組(8 位元 區塊)的並行輸出組成,其中並行度會根據吞吐量需求自動推導而出。

Operator Restrictions

  • 此運算子不支援空影像,即沒有像素的影像。

  • 不允許輸入線段長度各異的圖像。

  • 該運算子的最小輸入影像寬度取決於輸入並行度。 最小輸入影像寬度至少為輸入並行度的兩倍。最小輸入 影像寬度的計算方式如下:

    1. 根據輸入並行度:找出第一個等於或 大於輸入並行度的 8 的倍數。

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

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

    步驟 3 的結果即為該運算子所需的 最小輸入影像寬度。

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

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


    例如,若輸入並行度為 4,則 最小輸入影像寬度為 12。

    若輸入並行度為 12,則最小 輸入影像寬度為 24。

[提示] 優化操作員吞吐量

若輸入並行度大於 8,資料吞吐量將取決於 輸入影像的大小。透過以下影像大小 (OptimalSize)可達到最大的資料吞吐量:

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

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

PathCount = ceil(Par/8)

間隔大小:大於 7 的下一個值,且與 路徑計數 沒有公因數。

在內部處理時,運算子總是採用 為 8 的倍數的並行度。根據輸入並行度的不同,內部 並行度轉換可彌補部分頻寬損失。頻寬損失 僅發生在幀的結尾處。

由於壓縮影像資料的大小無法 預測,因此壓縮幀的最後一個輸出資料位元組可能無法與 輸出並行度對齊。因此,幀的最後一個資料向量可能包含隨機的虛擬 值。為了標示幀的實際結束位置,將使用 JPEG 標準中定義的 EOI(影像結束)標記。 EOI 標記由兩個位元組組成。每個幀的倒數第二個位元組為 0xFF,而每個幀的最後一個位元組為 0xD9。

為了優化影像吞吐率(頻寬),操作員會在 一啟動標頭生成時,便立即輸出標頭——甚至在影像資料抵達操作員的 輸入端之前。如此一來,由於標頭是預先傳輸的,因此標頭資料的傳輸 不會中斷影像資料的傳輸。 此做法的缺點在於, 操作員的輸出傳輸會比實際影像資料的傳輸更早開始。這在特定情況下可能會 造成困擾:

  • 在 JPEG_Encoder 之後直接使用 SourceSelector 運算子: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 輸入。幀 ID 用於識別確切的、 已遺失或遭截斷的幀。第三個封包標示所發生錯誤的類型。 位元 0 標示 幀是遺失(位元 0 = 1)還是被截斷(位元 0 = 0)。第三個封包的其餘 15 位元 僅在事件遺失時使用,而這種情況只會發生在事件發生速度過快 以致 CPU 無法處理時。第三個封包的位元 1 標示任何一次 TruncatedEvent 那是 已遺失的,且同一封包的 Bit2 會標記任何一次 LostEvent 那已經遺失了。 此外,關於 LostEvents 那些已遺失的位元中,Bit[15:3] 構成了一個計數器,用以儲存 的 LostEvents 已遺失的。若計數器值為零,則遺失的—LostEvent-計數器 已發生溢出。由於截斷的幀會導致 JPEG_Encoder 輸出資料,但遺失了一幀 則不然,VA 事件僅統計遺失的幀數 遺失的活動.

溢出事件資料

圖 415. 溢流事件資料


I/O Properties

Property Value
Operator Type M
Input Link I,資料輸入
Output Link O,資料輸出

Supported Link Format

Link Parameter Input Link I Output Link O
Bit Width 8 8
Arithmetic 無號數 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)。

Parameters

Quality
Type 靜態/動態寫入參數
Default 50.00
Range [1.00 - 100.00 %], {-1}, 步長 = 0.01%

透過此參數,可調整 JPEG 壓縮的品質。 量化矩陣是根據百分比值,運用上述公式 計算得出的。計算出的量化值可從參數 quantization_matrix 中讀取。 此參數為動態參數,僅應在小程式的閒置期間進行變更。

Quality 可設定的範圍為 1 至 100。寫入此參數 將覆寫先前透過參數 LuminanceQuantization 對量化矩陣所做的手動變更。若從 Quality讀取的值為 -1 時,表示 已對量化矩陣進行手動調整。

品質參數是定義編碼器壓縮比的主要依據。 亮度表將根據指定的品質自動計算,且可 讀取回原值。不過,亦可直接修改亮度表。若發生此情況, 品質參數將自動變更為 -1,以表示該參數已不再有效, 且目前正處於手動覆寫表的模式。 若使用者希望優化資源使用效率,可將品質與 量化表設定為靜態模式。僅能針對品質參數進行 靜態與動態變更的切換。量化 表的設定將自動遵循品質類型,且無法 手動覆寫。當品質設定為靜態時,操作員將根據品質設定 來決定輸出並行度。 在大多數情況下,輸出並行度將 相較於動態模式有所降低,這雖能顯著減少 FPGA 資源 消耗,但代價是必須放棄在 執行期間變更壓縮率的靈活性。

亮度量化
Type 遵循Quality 中的類型(動態或靜態)寫入參數
Default 無
Range [1 - 255]

品質值會自動計算為 [1.00 - 100.00] 範圍內的數值;若手動設定,品質值將 被設為無效值 -1。

包含標頭
Type 靜態寫入參數
Default 是
Range [是,否]

JPEG 標頭預設會包含在壓縮資料流中。不過,您 可以停用此功能。若將參數 IncludeHeader設定為 NO,則 JPEG 參數 ImageHeight 和 ImageWidth 將被停用。若將參數 IncludeHeader設定為 YES,則會包含標頭,且您 可以決定標頭參數應為靜態值,還是必須為動態值。 若設定為 靜態,影像寬度與影像高度的數值將被靜態嵌入至 標頭中,且無論輸入影像尺寸為何,皆無法變更。若設定為動態,您 可在執行期間變更影像寬度與影像高度的數值。 請注意 這些標頭參數不會自動更新為輸入影像的大小。若您 在執行期間使用尺寸會動態變化的影像來執行此運算子,您 事後將必須對產生的標頭進行修補。若您將 ImageHeight 和 ImageWidth 兩者皆設定為「靜態」,將可略微減少 FPGA 資源的使用量。

ImageWidth
Type 靜態/動態寫入參數
Default 1024
Range 1 - 2¹⁶-1

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

參數ImageWidth僅用於 根據參數 IncludeHeader 的說明來產生 JPEG 影像標頭。

ImageHeight
Type 靜態/動態寫入參數
Default 1024
Range 1 - 2¹⁶-1

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

參數ImageHeight僅用於 根據參數 IncludeHeader 的說明來產生 JPEG 影像標頭。

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

該處理器可直接接在攝影機操作員之後。在此情況下, InfiniteSource參數必須設定為 ENABLED。如此一來, 該處理器將執行主動式溢出管理,並透過 VA 事件系統向 軟體回報溢出狀況。 溢出僅可能發生於兩種情況:操作器 後方的接收端停止/暫停傳輸,或是輸入影像的高度並非 8 條線的倍數。在後一種情況下,操作器必須補足缺失的行數,以 依照 JPEG 標準的要求,完成最後一行 JPEG 區塊。

更多資訊請參閱「無限來源/連接攝影機」。

Examples of Use

以下範例展示了 JPEG_Encoder 運算子的用法:

More Information

以下為所使用的哈夫曼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" } };