Vivado的高層次綜合功能將幫助您為嵌入式視頻應用設計更好的排序網絡。
從汽車到安全系統再到手持設備,如今采用嵌入式視頻功能的應用越來越多。每一代新產品都需要更多的功能和更好的圖像質量。但是,對于一些設計團隊來說,實現高質量的圖像并非易事。
作為賽靈思的一名DSP設計現場應用工程師,我經常被問到有關IP和高效視頻濾波實現方法這方面的問題。我發現利用最新Vivado?設計套件的高層次綜合(HLS)功能,很容易在任何賽靈思7系列All Programmable器件中實現基于排序網絡的高效中值濾波方法。
在詳細探討該方法之前,我們先來回顧一下設計人員在圖像完整性方面所面臨的一些挑戰以及解決這些問題常用的濾波技術。
數字圖像噪聲大多出現在系統獲取或傳輸圖像的過程中。例如,掃描儀或數碼相機的傳感器和電路可以產生幾種類型的不規則噪聲。通信通道中的隨機比特錯誤或模數轉換器錯誤會導致特別麻煩的“脈沖噪聲”。這種噪聲經常被稱為胡椒鹽(salt-and-pepper)噪聲,因為它以隨機白點或黑點的形式出現在顯示器的圖像表面,嚴重降低了圖像質量(圖1)。
為降低圖像噪聲,視頻工程師通常會在設計中應用空間濾波器。這些濾波器利用噪聲點周圍像素的優質特性或數值對圖像中渲染較差的像素進行替換或加強。空間濾波器主要分為線性和非線性兩種。最常用的線性濾波器被稱為均值濾波器。它用鄰近像素的均值替換每個像素值。這樣,渲染較差的像素就可根據圖像中其它像素點的平均值得到改善。均值濾波器能以低通方式快速去除圖像噪聲。但是,該方式通常伴有副作用——使整體圖像的邊緣變得模糊。
大多數情況下,非線性濾波法比線性均值濾波法更好。非線性濾波特別善于消除脈沖噪聲。最常用的非線性濾波器是次序統計濾波器。而最受歡迎的非線性次序統計濾波器是中值濾波器。
中值濾波器廣泛用于視頻與圖像處理,因為此種濾波器具有出色的降噪能力,而且模糊程度比相同尺寸的線性平滑濾波器低得多。與均值濾波器類似,中值濾波器也要依次分析圖像中的每個像素,并觀察其鄰近的像素以判定該像素是否能代表其周圍像素。但是,中值濾波器并非簡單地將像素值用周圍像素的平均值進行替換,而是用周圍像素值的中值來替換。由于中值必須是鄰近某個像素的實際值,因此中值濾波器在跨越邊緣時不會創建新的虛擬像素值(避免了均值濾波器的邊界模糊影響)。因此,中值濾波器在保留銳邊方面比其它任何濾波器做得都要好。這種濾波器在計算中值時,首先將周圍窗口中的所有像素值按數值大小順序進行排序,然后用中間像素值替換待過濾的像素(如果待計算區域包含偶數個像素,那么使用中間兩個像素的平均值)。
例如,假設一個3x3像素窗口以值為229的像素為中心,該窗口值如下
39 83 225
5 229 204
164 61 57
我們可以對像素進行排序,獲得順序列表為5 39 57 61 83 164 204 225 229。
中值就是位于中間的像素值,即83。在輸出圖像中用該值替代初始值229。圖2表明在圖1噪聲輸入圖像中應用3x3中值濾波器后的效果。待過濾像素周圍的窗口越大,濾波效果越顯著。
中值濾波器具備出色的降噪能力,因此也被廣泛應用于掃描速率視頻轉換系統的內插級,例如為實現隔行視頻信號而將場速率從50Hz轉換為100Hz的運動補償內插程序,或者隔行至逐行轉換中的邊緣定向內插程序。如欲了解有關中值濾波器更詳盡的介紹,有興趣的讀者可以參考 [1]和 [2]。
在運用中值濾波器時最為關鍵的是確定使用哪種排序方法,以獲得用來生成每個輸出像素的像素排序列表。排序過程需要大量計算時鐘周期。
目前,賽靈思在Vivado設計套件中可提供高層次綜合。我通常會告訴人們,可以根據排序網絡概念在C語言中運用一種簡單而有效的方法來設計中值濾波器。我們可使用Vivado HLS [3]來獲得Zynq?-7000 All Pro-grammableSoC的FPGA架構的實時性能 [4]。
下面的內容里,我們假設圖像格式是每像素8位,每行1,920像素,每幀1,080行,幀速率為60Hz,因此最小像素速率至少為124MHz。不過,為了設置一些設計難度,我將要求Vivado HLS工具提供200MHz的目標時鐘頻率,如果得到比124MHz更大的頻率值效果會更好(由于實際視頻信號中還包含空白數據,因此時鐘速率比活動像素所要求的速率高)。
什么是排序網絡?
排序是指將陣列中的元素按照升序或降序的方式重新進行排列的過程。排序是很多嵌入式計算系統中最重要的操作之一。
由于排序在眾多應用中起到關鍵作用,因此很多科學文獻中的大量文章都對眾所周知的排序方法的復雜性和速度進行了分析,例如冒泡排序、希爾排序、歸并排序和快速排序。對于大數據集來說快速排序是速度最快的排序算法 [5],而冒泡排序是最簡單的。通常,所有這些技術都應該以軟件任務的形式在RISC CPU上運行,而且每次只執行一個對比。它們的工作負載不是恒定的,而是取決于有多少輸入數據已部分排序。例如,需要對一套N個樣本進行排序,假設快速排序的計算復雜性在最差、一般和最好的情況下分別是N2、NlogN和NlogN。同時,冒泡排序的復雜性分別是N2、N2和N。不得不承認我還尚未發現關于此類復雜性數字的統一觀點。但在我讀過的有關此問題的所有文章中似乎都贊同一個觀點,那就是計算某種排序算法的復雜性并不簡單。這本身似乎成為了尋找備選方案的主要原因。
在進行圖像處理時,我們需要在排序方法上獲得確定的行為,以便以恒定的吞吐量產生輸出圖片。因此,上述算法都無法成為采用Vivado HLS的FPGA設計的理想備選方案。
排序網絡可通過使用并列執行實現更快的運行速度。排序網絡的基礎構成模塊是比較器。比較器是一種簡單組件,能對a和b兩個數據進行排序,然后將最大值和最小值分別輸出到頂部和底部輸出結果中,必要時還可進行交換。排序網絡對于經典排序算法的優勢在于比較器的數量在給定輸入數量下是固定的。因此,排序網絡在FPGA硬件中易于實現。圖3舉例說明了一個針對五個樣本的排序網絡(采用賽靈思System Generator生成[6])。需要注意到的是處理延遲正好是五個時鐘周期,且與輸入樣本數值無關。此外還應注意到右側的五個并行輸出信號包含排序后的數據,其中最大值在頂部,最小值在底部。
在C語言中通過排序網絡實現中值濾波器是很簡單的,如圖4中的代碼所示。Vivado HLS指令被嵌入到C語言代碼自身內(#pragma HLS)。Vivado HLS只需要兩個優化指令即可生成最佳RTL代碼。首先是利用1的初始間隔 (II)將整個函數流水線化,使輸出像素速率等于FPGA時鐘速率。第二步優化是將像素窗口重新劃分為單獨的寄存器,以便同步并行訪問所有數據,從而提高帶寬。
頂層函數
圖5中的代碼段是中值濾波器的初級實現,我們將其作為參考。最里面的回路已進行流水線化處理,以便在任何時鐘周期內都能生成一個輸出像素。為了生成延遲估計報告,我們需要利用TRIPCOUNT指令通知Vivado HLS編譯器有關回路L1和L2中可能出現的迭代次數,因為它們是“不受控”的。也就是說,假設該設計可在運行期間處理低于最大允許分辨率為1,920 x 1,080像素的圖像分辨率,這些環路的極限值就是圖片的高度和寬度,而這兩個值在編譯期間都是未知的。
在C語言代碼中,待濾波的像素窗口可訪問圖像中不同的行。因此,利用存儲器位置來降低存儲帶寬需求的優勢比較有限。盡管Vivado HLS可對代碼進行綜合,但吞吐量并未達到最優值,如圖6所示。回路L1_L2的初始化間隔(最里面回路L2完全展開的結果,由HLS編譯器自動執行)為五個時鐘周期,而非一個,因此得到的輸出數據速率無法支持實時性能。從整個函數的最大延遲中也能明確這一點。在一個5納秒的目標時鐘周期中,用來計算輸出圖像的周期數量為10,368,020,這意味著幀速率為19.2Hz而非60Hz。正如參考文獻[7]中詳細描述的,Vivado HLS設計人員必須明確地將視頻線路緩沖器的行為代碼寫入用于生成RTL的C語言模型中,因為HLS工具無法自動將新存儲器插到用戶代碼中。
全新的頂層函數C語言代碼如圖8所示。由于當前的像素坐標(行,列)顯示為in_pix[r][c],因此需在坐標(r-1, c-1)中的待濾波輸出像素周圍創建一個滑動窗口。對于3x3大小的窗口,其結果是out_pix[r-1][c-1]。需要注意到的是當窗口尺寸為5x5或7x7的時候,輸出像素坐標分別為(r-2, c-2)和(r-3, c-3)。靜態陣列線路_緩沖器可存儲KMED視頻線路數量等同于中值濾波器中垂直樣本的數量(當前情況下的數量為3個);而且由于靜態C語言關鍵字的原因,Vivado HLS編譯器可自動將內容映射到FPGA雙端口Block RAM (BRAM)元件中。
這樣僅需很少的HLS指令就可實現實時性能。需對最里面的回路L2進行流水線化處理,以便在任何時鐘周期內都能生成一個輸出像素。輸入與輸出圖像陣列in_pix和out_pix被映射為RTL中的FIFO流接口。將該線路_緩沖器陣列劃分成多個KMED獨立陣列,以便Vivado HLS編譯器將每個陣列映射到獨立的雙端口BRAM中。由于這樣會有更多的可用端口,從而增加了載入/存儲操作次數(每個雙端口BRAM在每個周期內能完成兩次載入或存儲操作)。圖7是Vivado HLS性能估算報告。目前,最大延遲為2,073,618個時鐘周期。在5.58ns的估計時鐘周期下,我們可以獲得86.4Hz的幀速率。這已超越了我們的需求值!回路L1_L2正如我們所希望的那樣得到II=1。應注意到的是需要兩個BRAM以存放KMED線路緩沖存儲器。
利用高層次綜合進行架構探索
在我看來,Vivado HLS的最佳特性之一是能夠通過改變工具的優化指令或C語言代碼本身這樣的方式來探索不同設計架構并對性能進行權衡,從而實現富有創造性的設計自由度。兩種操作方式都非常簡單而且并不耗時。
如果需要更大的中值濾波器窗口該怎么做?例如需要5x5而不是3x3的窗口尺寸。我們只需將KMED在C語言代碼中的定義從“3”變為“5”,并再次運行Vivado HLS即可。圖9是單獨在3x3、5x5和7x7三種窗口尺寸情況下對中值濾波器例程進行綜合所得到的HLS對比報告。在所有三種情況下,例程已完全流水線化 (II=1),并且滿足目標時鐘周期;延遲分別為9、25和49個時鐘周期,與人們對于排序網絡的預期表現相符。顯然,由于待排序的數據總量從9增至25甚至達到49,因此所使用的資源(觸發器和查找表)也相應增加。
由于獨立函數已完全流水線化,因此頂層函數的延遲保持恒定,同時當增大窗口尺寸的時候時鐘頻率會略有減小。到目前為止我們只討論了將Zynq-7000 All Programmable SoC作為目標器件的這種情況,但采用Vivado HLS時我們可在相同項目中輕松嘗試不同目標器件。例如,如果我們選用Kintex?-7 325T并對相同的3x3中值濾波器設計進行綜合,所用的布局布線資源包括兩個BRAM、一個DSP48E、1,323個觸發器和705個查找表(LUT),時鐘和數據速率為403MHz;而使用ZynqSoC器件時,則需使用兩個BRAM、一個DSP48E、751個觸發器和653個查找表,時鐘和數據速率為205MHz。
最后,如果我們想查看3x3中值濾波器處理每樣本為11位(而非8位)灰色圖像時的資源使用情況,我們可通過應用ap_int C++類型來改變pix_t數據類型的定義,這樣就可規定任意位寬的定點數。我們只需通過啟動C語言預處理符號GRAY11就可重新編譯該項目。在這種情況下,ZynqSoC上的資源使用估算量為四個BRAM、一個DSP48E、1,156個觸發器和1,407個查找表。圖10給出了最后兩種情況的綜合估算報告。
短短數個工作日
此外,我們還可以看到,對于具有不同窗口尺寸甚至不同位數/像素的中值濾波器,生成時序和面積估算值到底有多簡單。尤其是在使用3x3 (或5x5)中值濾波器的情況下,由Vivado HLS自動生成的RTL只在ZynqSoC器件上占用很小面積(-1速度級),布局布線完成后,FPGA時鐘頻率為206(5x5版本為188)MHz,有效數據速率為206(或188)MSPS。
得到這些結果所需的總設計時間僅為五個工作日。其中大部分時間都用于構建MATLAB?和C模型,而非運行Vivado HLS工具本身;后者所需時間不足兩個工作日。
評論