彭日光 彭爽 杜琦
(中電長城圣非凡信息系統(tǒng)有限公司湖南計算機研發(fā)中心 湖南省長沙市 410000)
在基于OpenCV 的圖像處理系統(tǒng)中,圖像的處理幾乎都是通過調(diào)用底層庫函數(shù)來實現(xiàn),為了提高系統(tǒng)的性能來滿足最終用戶的需求,需要提高圖像處理庫函數(shù)的計算性能,可以對圖像處理庫函數(shù)進行硬件加速。硬件加速的首要工作是對軟硬件進行分區(qū),軟硬件分區(qū)的工作可以能會反復(fù)迭代,來滿足系統(tǒng)的吞吐性能和靈活性要求,而開發(fā)人員最關(guān)注的部分往往是算法的最終實現(xiàn)和算法模塊的優(yōu)化。這就需要采用一種針對于函數(shù)庫的硬件加速方法,減少系統(tǒng)設(shè)計的軟硬件分區(qū)工作,而將系統(tǒng)設(shè)計的工作專注到算法的優(yōu)化和軟件功能實現(xiàn)上。
對OpenCV 函數(shù)庫進行硬件加速,常采用的開發(fā)流程:首先進行軟硬件分區(qū),來決定將哪些部分用于軟件實現(xiàn),哪些部分放入硬件加速;然后將劃分為硬件實現(xiàn)的功能使用RTL(寄存器傳輸級)代碼來開發(fā),或是使用HLS(高層次綜合工具)將C/C++代碼綜合成中可實現(xiàn)的IP;再是搭建DataMover和接口;最后才是進行驅(qū)動程序的開發(fā)和上層應(yīng)用軟件開發(fā)。
對于劃分到硬件的庫函數(shù)硬件加速,實際上是將函數(shù)庫代碼轉(zhuǎn)化為可綜合的代碼,通常采用兩種實現(xiàn)方法:利用FPGA 廠商或者第三方提供的可綜合的圖像函數(shù)庫中的IP代替原始的庫函數(shù),這些專用的函數(shù)庫IP 能很好地綜合為RTL 代碼,進而實現(xiàn)圖像處理加速;另外一種方法工程師為實現(xiàn)對應(yīng)的函數(shù)庫功能,自己編寫函數(shù)庫對應(yīng)的代碼,通過使用RTL 代碼來開發(fā)。如果采用第一種方法,有可能需要購買廠商或者第三方提供的專有函數(shù)庫,并且提供的函數(shù)庫也可能并不開源,開發(fā)人員還需要熟悉硬件函數(shù)庫功能,以及調(diào)用的接口;而采用第二種方式自己編寫RTL 代碼來改寫庫函數(shù),又存在不能充分利用原始OpenCV 函數(shù)庫的計算特性,自己編寫的函數(shù)的計算效率遠低于原有庫函數(shù)的計算性能,并且底層庫函數(shù)之間存在調(diào)用和依賴關(guān)系,如果要將整個調(diào)用層次的底層函數(shù)都改寫成RTL 代碼,工作量非常的大。此外,無論是采用廠商或者第三方提供的IP,還是自己編寫RTL 代碼來綜合成IP,這兩種方式都需要軟硬件開發(fā)人員同時參與,并且還需要進行手動軟硬件的集成,開發(fā)流程比較復(fù)雜,開發(fā)效率比較低。
針對現(xiàn)有技術(shù)的不足,本論文提供了一種基于Xilinx SDSoC 平臺,對OpenCV 函數(shù)庫中圖像處理函數(shù)進行硬件加速的方法,該方法在保持原有函數(shù)庫框架不變的基礎(chǔ)上,提升了計算性能,而且不需要硬件人員參與,也不需要進行手動軟硬件集成,簡化了開發(fā)流程,提高了開發(fā)效率。為了實現(xiàn)對函數(shù)庫的硬件加速,首要工作就是需要對軟硬件進行協(xié)同設(shè)計。
借助Xilinx 提供的SDSoC 開發(fā)工具,將需要加速的應(yīng)用程序函數(shù)分配到FPGA 上執(zhí)行,使之成為硬件加速函數(shù),然后通過工具自動搭建DataMover、軟件驅(qū)動程序和硬件連接接口,使得軟件函數(shù)和硬件函數(shù)之間通訊工作得到簡化,工程師將工作聚焦到C/C++應(yīng)用層面的算法工作上。基于SDSoC 的OpenCV 庫函數(shù)軟硬件協(xié)同設(shè)計開發(fā)流程如圖1所示。
圖1:SDSoC 軟硬件協(xié)同設(shè)計流程
首先根據(jù)客戶需求,定義C/C++的圖像處理應(yīng)用系統(tǒng);開發(fā)應(yīng)用程序,通過對多個庫函數(shù)的調(diào)用來實現(xiàn)系統(tǒng)功能;在所調(diào)用庫函數(shù)中,選擇哪些庫函數(shù)需要硬件加速,哪些庫函數(shù)采用現(xiàn)有的軟件實現(xiàn),即進行軟硬件分區(qū);庫函數(shù)硬件加速則是根據(jù)軟硬件劃分的結(jié)果,將需要硬件加速的庫函數(shù),通過采用本論文提出的庫函數(shù)硬件加速方法,將庫函數(shù)移到應(yīng)用層實現(xiàn);庫函數(shù)被移植到應(yīng)用層之后,再通過Xilinx 提供的SDSoC 工具,將應(yīng)用層加速函數(shù)放入可編程邏輯中加速,該工具還會自動搭建DataMover、配置軟件驅(qū)動程序、生成軟硬件系統(tǒng)連接接口和相關(guān)的庫,最終生成PL 上可執(zhí)行的比特流文件和PS 上可執(zhí)行的ELF 文件;最后將生成的文件下載到嵌入式設(shè)備上運行測試,如果測試的性能不達標,可以快速選擇不同的硬件加速的功能塊,探索不同的軟硬件分區(qū)方案,或是通過pragma 指示符等手段來指導(dǎo)工具產(chǎn)生不同的系統(tǒng)配置方法來進一步優(yōu)化系統(tǒng)設(shè)計。軟硬件協(xié)同設(shè)計開發(fā)流程中的一項關(guān)鍵工作就是將OpenCV 庫中需要硬件加速的函數(shù),在保持庫框架不變的前提,使之加載到FPGA上執(zhí)行。
在Xilinx 提供的SDSoC 平臺基礎(chǔ)之上,對庫中圖像處理函數(shù)進行硬件加速,首先需要識別出庫中需要進行硬件加速的高強度計算功能的庫函數(shù),然后采用特殊的技術(shù)處理方式,將庫中的需要加速的函數(shù)移植到應(yīng)用代碼中去實現(xiàn),最后再利用FPGA 來對應(yīng)用程序的高強度功能代碼進行硬件加速,庫函數(shù)加速流程如圖2 所示。
圖2:OpenCV 庫函數(shù)加速流程
如流程圖2 所示,對庫中圖像處理函數(shù)進行硬件加速,包括以下步驟:
(1)將庫中需要進行硬件加速的圖像處理函數(shù)的復(fù)雜運算代碼抽取出來,封裝成新的函數(shù),確保新的函數(shù)中沒有再次對庫中的其它函數(shù)進行調(diào)用,都是基本的算術(shù)邏輯運算;
(2)在抽取的硬件加速的圖像處理函數(shù)所在文件中定義與新抽取的函數(shù)對應(yīng)的函數(shù)指針類型,函數(shù)指針類型的函數(shù)參數(shù)應(yīng)與新抽取的函數(shù)的參數(shù)保持一致;
(3)在抽取的硬件加速的圖像處理函數(shù)所在文件中定義函數(shù)指針類型對應(yīng)的靜態(tài)全局變量(函數(shù)指針類型的實例);
(4)針對定義的靜態(tài)全局變量,定義一個可供應(yīng)用代碼調(diào)用的賦值函數(shù),用來給對應(yīng)的靜態(tài)全局變量賦值,并且確保賦值函數(shù)的函數(shù)參數(shù)的類型就是靜態(tài)全局變量對應(yīng)的函數(shù)指針類型,這樣應(yīng)用程序就可以調(diào)用庫中的賦值函數(shù),對靜態(tài)全局變量進行賦值;
(5)修改庫中步驟(1)確定的需要進行硬件加速的圖像處理函數(shù),注釋掉其對新抽取的函數(shù)的調(diào)用,將原有的調(diào)用參數(shù)傳遞給步驟(3)中定義的對應(yīng)的函數(shù)指針類型的靜態(tài)全局變量,從而改成對靜態(tài)全局變量的函數(shù)指針的調(diào)用;
(6)重新交叉編譯庫,生成動態(tài)鏈接庫,供應(yīng)用層代碼調(diào)用;
(7)在應(yīng)用代碼中,定義需要硬件加速的函數(shù),其函數(shù)參數(shù)與步驟(2)中定義的函數(shù)指針類型的函數(shù)參數(shù)保持一致,其完成的功能與步驟(1)中抽取出來的函數(shù)的功能相同,并且確保其內(nèi)部不再調(diào)用庫函數(shù),這樣就將原來庫中完成的功能,改成應(yīng)用代碼來實現(xiàn);
(8)應(yīng)用代碼Main 函數(shù)在初始化的時候,首先調(diào)用動態(tài)鏈接庫中的賦值函數(shù),將步驟(7)中定義的硬件加速函數(shù)作為參數(shù)傳給該賦值函數(shù),從而實現(xiàn)對庫中對應(yīng)靜態(tài)全局變量的賦值,在應(yīng)用代碼對庫中圖像處理函數(shù)進行函數(shù)調(diào)用時,庫中硬件加速函數(shù)的內(nèi)部代碼會調(diào)用靜態(tài)全局變量的函數(shù)指針,由于此時靜態(tài)全局變量的函數(shù)指針已被賦值函數(shù)賦值為應(yīng)用代碼中的硬件加速函數(shù),從而實現(xiàn)對應(yīng)用代碼中的硬件加速函數(shù)的調(diào)用;
(9)通過Xilinx SDSOC 開發(fā)平臺工具,將步驟(7)中定義的硬件加速函數(shù)改成由FPGA 硬件邏輯來實現(xiàn)。
步驟(1)到(6)在保持OpenCV 低層庫框架不變的基礎(chǔ)上,通過函數(shù)指針調(diào)用替換原有功能函數(shù),生成新的動態(tài)庫;步驟(7)和步驟(8)在應(yīng)用層完成原有低層庫函數(shù)的功能;步驟(9)實現(xiàn)對應(yīng)用層函數(shù)的硬件加速。
使用Xilinx SDSoC 開發(fā)環(huán)境集成的高層次綜合工具Vivado HLS在ZYNQXC7Z020-2CLG400I 平臺上對OpenCV 自適應(yīng)閾值庫函數(shù)進行硬件加速,并且對實驗結(jié)果進行分析,來對比本文提出的硬件加速方法與原有軟件實現(xiàn)方法,驗證本文提出的硬件加速是否能夠提高系統(tǒng)的計算性能。
Vivado HLS 工具提供100MHz 的目標時鐘頻率,對24位深度,每行640 個像素,每列480 個像素的JPG 格式的圖片進行均值濾波處理。通過使用工具提供的pragma 指示符來對硬件指令進行優(yōu)化,使得圖片的像素矩陣能夠被并行化處理,在計算濾波窗口像素均值時,采用滑動窗口技術(shù),使得硬件函數(shù)內(nèi)執(zhí)行指令完全達到流水線化(II=1)。
按照庫函數(shù)硬件加速的流程圖,對庫中的自適應(yīng)閾值函數(shù)進行硬件加速,具體實施步驟如下:
(1)將adaptiveThreshold 函數(shù)內(nèi)部的復(fù)雜運算邏輯功能,抽取出一個新的函數(shù);
int sw_adaptiveThreshold(pix_t gray[][MAX_WIDTH],pix_t in_pix[][MAX_WIDTH], pix_t out_pix[][MAX_WIDTH],short int height, short int width, int _Idelta, int _MaxValue);
(2)定義函數(shù)指針類型,其函數(shù)參數(shù)與新抽取函數(shù)的函數(shù)參數(shù)保持一致;
typedef void (* pfun_adaptiveThreshold)(pix_t gray[][MAX_WIDTH], pix_t in_pix[][MAX_WIDTH], pix_t out_pix[][MAX_WIDTH], short int height, short int width, int _Idelta, int_MaxValue);
(3)定義一個該函數(shù)指針類型的靜態(tài)全局變量;
static pfun_adaptiveThreshold pfun_instance;
(4)定義一個可供應(yīng)用程序調(diào)用的庫函數(shù),用來對靜態(tài)全局變量賦值,并且函數(shù)參數(shù)類型就是上述定義的函數(shù)指針類型;
(5)修改庫中需要進行硬件加速的圖像處理函數(shù),將其內(nèi)部改成對靜態(tài)全局變量函數(shù)指針的調(diào)用;
(6)重新交叉編譯庫,生成新的動態(tài)鏈接庫,供應(yīng)用程序調(diào)用;
(7)在應(yīng)用代碼中,定義需要硬件加速的函數(shù),函數(shù)參數(shù)與步驟2 中定義的函數(shù)指針類型的函數(shù)參數(shù)保持一致;
(8)在應(yīng)用代碼中調(diào)用動態(tài)鏈接庫內(nèi)的賦值函數(shù),將硬件加速函數(shù)作為參數(shù)傳給該賦值函數(shù),然后調(diào)用庫中的圖像處理函數(shù)進行圖像處理;
(9)最后在Xilinx SDSOC 開發(fā)平臺中,將硬件加速函數(shù)hw_adaptiveThreshold_impl 改成由FPGA 實現(xiàn)的硬件加速函數(shù)。
庫函數(shù)被移植到應(yīng)用層之后,如果針對于特定的應(yīng)用場景進行加速,則可以對移植后的應(yīng)用程序進行定制,只需要將上層函數(shù)的參數(shù)接口和底層庫中的函數(shù)接口保持一致即可,這樣也給應(yīng)用程序提供了很大的優(yōu)化空間。自適應(yīng)閾值應(yīng)用層硬件加速包括兩個硬件函數(shù),一個為根據(jù)窗口大小計算窗口像素均值的底層函數(shù),另外一個是頂層函數(shù),通過滑動窗口技術(shù),計算像素矩陣中每一個像素的均值。樣例函數(shù)如下所示:
在將圖片從24 位像素格式轉(zhuǎn)換成8 位像素格式之后,循環(huán)10 次進行均值濾波計算,來比較采用本文提出加速方法的均值濾波函數(shù)計算時間和原有軟件實現(xiàn)的均值濾波函數(shù)計算時間。對于均值濾波硬件加速函數(shù),首先可以通過Vivado HLS 性能評估工具,對硬件函數(shù)進行時間性能分析,從圖3 性能評估結(jié)果可以看出,采用本文方法的均值濾波函數(shù),圖片所有像素均值計算一共為307200(640*480)個時鐘周期,即圖片的每一個像素計算其均值只需要一個時鐘周期的處理時間??梢钥闯?,雖然需要根據(jù)窗口大小來計算像素均值,但計算窗口像素均值都在一個時間周期內(nèi)完成,對像素矩陣的處理,指令已經(jīng)達到流水化。
圖3:均值濾波硬件函數(shù)性能評估
在實際硬件平臺上進行性能對比測試,使用原始函數(shù)庫進行計算,10 次均值濾波計算時間為3S 左右,而采用本文提出的硬件加速函數(shù)進行計算,10 次均值濾波的處理時間僅為0.3S 左右。從而可以看出,通過本文的硬件加速方法,計算速度提高了10 倍左右。在處理數(shù)據(jù)的準確性方面,通過對兩種方法生成圖片的像素進行比較分析,下圖左邊為軟件均值濾波的處理結(jié)果,右邊為硬件加速濾波的處理結(jié)果,通過對比圖4 圖像矩陣的像素值,對圖片中心區(qū)域的處理,硬件加速處理的結(jié)果和軟件處理的結(jié)果幾乎完全一致,滿足設(shè)計時的準確性要求。
圖4:均值濾波軟硬件函數(shù)結(jié)果對比
本文研究使用基于SDSoC 軟硬件協(xié)同設(shè)計方法結(jié)合邏輯可編程FPGA,實現(xiàn)對OpenCV 庫函數(shù)硬件加速,來解決實時圖像處理軟件速度性能瓶頸的問題。該研究方法在保持現(xiàn)有庫函數(shù)框架不變的前提下,通過將庫函數(shù)實現(xiàn)移植到應(yīng)用層,再利用工具硬件加速其應(yīng)用程序,來提高實時圖像的處理性能。將該研究方法應(yīng)用于某手機玻璃廠抓取打磨玻璃的工程項目中,對圖像處理的邊緣檢測功能進行硬件加速,計算速度相比原有的軟件實現(xiàn),性能提高3 倍以上。更重要的是,采用該研究方法,無需硬件工程師參與,軟件工程師就能夠?qū)崿F(xiàn)硬件加速功能,并且無需關(guān)注軟硬件接口,只需要將重點工作專注到算法的優(yōu)化和軟件功能實現(xiàn)上。