張祖昊,王云光
(1.上海理工大學(xué) 醫(yī)療器械與食品學(xué)院,上海 200093;2.上海健康醫(yī)學(xué)院 醫(yī)療器械學(xué)院,上海 201318)
數(shù)字圖像處理技術(shù)在機器視覺和計算機視覺技術(shù)領(lǐng)域起著至關(guān)重要的作用。越來越多的領(lǐng)域不斷對圖像處理提出新的要求,在圖像處理算法復(fù)雜性持續(xù)增加的同時還要滿足圖像分辨率和每秒傳輸幀數(shù)(Frames Per Second,F(xiàn)PS)[1-3]要求。醫(yī)療領(lǐng)域的電子內(nèi)窺鏡需要在手術(shù)時將人體內(nèi)部的畫面實時且清晰地輸出到顯示屏上[4-5]。目前電子內(nèi)窺鏡的分辨率普遍在1 280×720 以上,因此對系統(tǒng)帶寬、數(shù)據(jù)吞吐率要求較高,軟硬件協(xié)同工作是最佳的解決方案。朱炎均[6]使用ZedBoard 完成320×240 分辨率視頻實時處理,由于沒有使用DMA 技術(shù),因此整體帶寬提升不多;李振宇[7]使用Zynq 完成VGA 格式1 280×720 分辨率視頻實時處理,但是由于輸出的不是HDMI 信號,因此應(yīng)用范圍較窄。雖然傳統(tǒng)的FPGA 可以利用其并行特性提高系統(tǒng)吞吐率,但在開發(fā)圖像處理算法時使用Verilog 效率很低[8-9],ARM+DSP 難以解決該問題。
本文采用Xilinx 公司的Zynq-7000 系列可編程(System On Chip,SOC)ARM+FPGA 異構(gòu)設(shè)計作為視頻圖像處理平臺,該平臺主要由處理系統(tǒng)(Processing System,PS)和可編程邏輯(Programmable Logic,PL)兩部分構(gòu)成[10]。其中PS部分包含兩塊ARM Cortex-A9 雙核處理器,負責(zé)系統(tǒng)控制;PL 部分由Xilinx 7 系列FPGA 構(gòu)成,負責(zé)視頻信號采集、處理、緩存和輸出工作。系統(tǒng)采用OV5640 作為圖像傳感器,HDMI 顯示器作為視頻輸出,使用Xilinx 公司的Vivado HLS作為圖像處理算法開發(fā)工具,將C/C++轉(zhuǎn)換成RTL Verilog代碼并封裝成IP,可在提高系統(tǒng)整體帶寬和吞吐率的同時,大大加快圖像處理算法的開發(fā)速度。
系統(tǒng)由采集、處理、緩存、顯示4 部分組成,系統(tǒng)結(jié)構(gòu)如圖1 所示。系統(tǒng)由PS 和PL 通過AXI4 總線連接協(xié)同完成。采集部分使用Zynq 的PS 端對OV5640 攝像頭的寄存器組發(fā)送不同寄存器值,完成攝像頭初始化工作。再通過Zynq的PL 端自定義OV5640 完成數(shù)據(jù)采集工作;圖像處理使用Xilinx HLS 開發(fā)工具,將C/C++轉(zhuǎn)換成Verilog 語言并封裝成IP,使用PL 將其例化;視頻緩存使用Xilinx 官方提供的VD?MA(Video Direct Memory Access)IP,實現(xiàn)3 幀畫面緩存,以避免畫面閃爍和撕裂等現(xiàn)象;視頻顯示通過Zynq 的PL 端輸出IP,將視頻信號以HDMI 的時序輸出。
由于Zynq 將ARM 與FPGA 集成在一起,開發(fā)工作既要設(shè)計ARM 的應(yīng)用程序,又要設(shè)計FPGA 部分的硬件邏輯設(shè)計,因此Zynq 開發(fā)需要遵循軟硬件協(xié)同開發(fā)方式,以達到提升開發(fā)效率和產(chǎn)品性能目的。Zynq-7000 系列嵌入式開發(fā)步驟如下:①在Vivado 中創(chuàng)建新的工程;②使用IP 集成器創(chuàng)建處理器系統(tǒng);③生成頂層HDL 并導(dǎo)出設(shè)計到SDK;④創(chuàng)建應(yīng)用測試程序;⑤設(shè)計驗證[11]。其中Vivado 是FP?GA 的硬件開發(fā),生成的頂層HDL 文件就是硬件設(shè)計生成的結(jié)果。將其導(dǎo)入到SDK 后再創(chuàng)建應(yīng)用測試程序,進行相應(yīng)的軟件開發(fā)。測試程序根據(jù)HDL 提供的BSP(Board Sup?port Package)板級支持包中提供的硬件資源完成指定任務(wù)。合理分配硬件和軟件的任務(wù)分工也是軟硬件協(xié)同開發(fā)十分重要的一步,本設(shè)計將OV5640 攝像頭和VDMA 初始化配置工作交給軟件處理,剩下所有視頻信號采集、處理和輸出工作全部交給硬件完成。
圖2 為使用VivadoIP 集成器創(chuàng)建的Block Designer 工程圖,其中的核心模塊是ov5640_capture_data_0,ov5640_so?bel_0,axi_vdma_0 和DVI_Transmitter_0,分別對應(yīng)采集、處理、緩存和顯示。下面分別從數(shù)據(jù)流通路和控制流通路介紹該硬件設(shè)計原理。
Fig.2 Vivado block design圖2 Vivado 塊設(shè)計
當(dāng)PS 將OV5640 配置完成后,其數(shù)據(jù)引腳就會在每個像素時鐘周期輸出一個8bit 的數(shù)據(jù)信號到ov5640_cap?ture_data_0 模塊的cam_data[7:0]輸入引腳。該模塊功能是采集攝像頭輸出的數(shù)據(jù)并將其從RGB565 格式轉(zhuǎn)換成視頻流RGB888 格式輸出。然后數(shù)據(jù)從ov5640_capture_data_0 的cmos_rgb 引腳輸出到v_vid_in_axis4s_0 模塊的vid_io_in 引腳。該模塊功能是將視頻信號轉(zhuǎn)換成AXI4-Stream 視頻協(xié)議信號[12]。經(jīng)過轉(zhuǎn)換后數(shù)據(jù)從v_vid_in_axis4s_0 的video_out 引腳輸出到HLS 圖像處理模塊的INPUT_STREAM 引腳,該模塊功能就是對視頻信號進行實時處理,可以嵌入一層或多層不同的HLS 模塊實現(xiàn)不同的圖像處理算法。經(jīng)過圖像處理后,數(shù)據(jù)從HLS 模塊的OUT?PUT_STREAM 引腳輸出到axi_vdma_0 的S_AXIS_S2MM 引腳。該模塊在PS 對其初始化配置完成后即可直接對DDR3進行讀寫操作,實現(xiàn)畫面的幀緩存功能[13]。VDMA 和DDR3 之間還需要通過AXI SmartConnect 和Zynq 的AXI HP總線進行連接,因此數(shù)據(jù)會從axi_vdma_0 模塊的M_AX?IS_MM2S 引腳流出到axi_smc 模塊的S01_AXI 引腳,再從M00_AXI 引腳流出到Zynq 模塊的S_AXI_HP0 引腳,此時即完成畫面幀緩存的數(shù)據(jù)通路。然后進行畫面輸出顯示數(shù)據(jù)流。當(dāng)一幀畫面緩存完成后,DDR3 中的數(shù)據(jù)就會通過Zynq 模塊的S_AXI_HP0 輸出到axi_smc 模塊的M00_AXI引腳,再從S00_AXI 引腳輸出到axi_vdma_0 模塊的M_AXI_MM2S 引腳,完成VDMA 模塊對DDR3 的讀操作。axi_vdma_0 接收到DDR3 數(shù)據(jù)后再從M_AXIS_MM2S 引腳輸出到v_axi4s_vid_out_0 模塊的video_in 引腳,該模塊功能與v_vid_in_axi4s_0 的功能相反,是將AXI4-Stream 協(xié)議信號格式轉(zhuǎn)換成視頻流信號格式[14]。經(jīng)過v_axi4s_vid_out_0模塊轉(zhuǎn)換后從vid_io_out 引腳輸出到DVI_Transmitter_0 模塊的Video_In 引腳,該模塊功能是將視頻流信號轉(zhuǎn)換成HDMI 信號格式輸出到HDMI 接口上,最后通過TMDS 引腳輸出到HDMI 顯示器,完成畫面輸出顯示的數(shù)據(jù)通路。
控制流通路所有的控制信號均由Zynq 模塊發(fā)出,系統(tǒng)需要完成的控制有:①OV5640 初始化配置;②VDMA 初始化配置;③整個系統(tǒng)的復(fù)位和時鐘信號。OV5640 的控制流通路通過Zynq 模塊的GPIO_0 引腳輸出到emio_sccb 引腳,來往于OV5640 的寄存器中寫配置信息。VDMA 時鐘控制流通路通過Zynq 模塊的M_AXI_GP0 引腳輸出控制信號到ps7_0_axi_periph 模塊的S00_AXI 引腳,該模塊是AXI Inter?connect 的一個實例,可讓Zynq 模塊同時與多個AXI4 總線協(xié)議模塊互聯(lián),在ps7_0_axi_periph 輸出端分出4 個AXI 輸出引腳,分別用來控制VDMA、axi_dynclk_0 和v_tc_0。其中axi_dynclk_0 是動態(tài)時鐘生成器實例,用來管理整個系統(tǒng)時鐘信號;v_tc_0 是視頻時序生成器實例,用來控制HD?MI 輸出時序。復(fù)位控制流通路通過Zynq 模塊的FCLK_RESET0_N 引腳輸出到rst_ps7_0_50M 模塊,該模塊是處理器系統(tǒng)復(fù)位實例,用來控制整個系統(tǒng)的復(fù)位工作。系統(tǒng)控制流通路通過這些控制信號使整個系統(tǒng)完成采集、處理、緩存和顯示功能。
本系統(tǒng)圖像處理模塊使用Vivado HLS 開發(fā),在HLS 中移植了大量的OpenCV 函數(shù)庫,可以調(diào)用移植后的OpenCV函數(shù)庫對圖像進行處理[15-16]。但是需要注意的是,HLS 中的OpenCV 函數(shù)庫與OpenCV 函數(shù)庫并不完全相同。OpenCV 函數(shù)是不能直接綜合的,因此必須由可綜合的庫函數(shù)替換,主要原因是OpenCV 函數(shù)涉及到動態(tài)內(nèi)存分配,在FPGA 中動態(tài)內(nèi)存分配是不可綜合的行為。圖3 為使用OpenCV 與HLS 視頻庫進行圖像處理流程。
Fig.3 Image processing flow of Opencv and HLS video library圖3 OpenCV 與HLS 視頻庫圖像處理流程
與傳統(tǒng)OpenCV 圖像處理相比,使用HLS 視頻庫進行圖像處理需要將OpenCV 格式的數(shù)據(jù)轉(zhuǎn)換成AXI 視頻格式,該操作通過IplImage2AXIvideo 函數(shù)完成;然后將AXI 視頻格式轉(zhuǎn)換成Mat 格式,該操作通過AXIvideo2Mat 函數(shù)完成;之后就可調(diào)用HLS 中移植的OpenCV 函數(shù)庫進行圖像處理。這里調(diào)用的是Sobel 強邊緣檢測對圖像處理效果進行測試,處理完之后再將Mat 格式轉(zhuǎn)換成AXI 視頻格式,最后還原成OpenCV 格式,這樣就完成了使用HLS 中OpenCV視頻庫對視頻圖像進行處理的過程。可以通過這個過程在PC 上使用一張圖像驗證圖像處理算法效果。當(dāng)驗證通過之后,再把圖中方框部分封裝成一個RTL 級IP 核,嵌入到前面的Vivado 硬件設(shè)計的Block Design 采集模塊和緩存模塊中間,即可以實現(xiàn)實時視頻圖像處理功能。
圖4 為PC 上使用HLS 進行Csimulation 處理的效果圖片,實現(xiàn)的是水平Sobel 梯度算子的掩膜計算??梢钥吹?,經(jīng)過圖像處理后,右圖很好地將原圖中垂直邊緣檢測出來,效果顯著。
Fig.4 Simulation processing effect of HLS video library on PC圖4 PC 上HLS 視頻庫仿真處理效果
SDK 軟件部分需要完成的工作有:①初始化EMIO;②初始化OV5640 攝像頭;③配置VDMA;④初始化顯示時序控制器;⑤設(shè)置顯示模式。圖5 是SDK 應(yīng)用程序設(shè)計流程。
SDK 中所有的工作都是通過調(diào)用BSP(Board Support Package)中的庫函數(shù)完成的,而該BSP 是根據(jù)前面的Vivado硬件設(shè)計部分提供的。首先初始化Zynq 上的兩個EMIO 引腳,將其用作SCCB 通信引腳,因為這里只需要對OV5640進行寫寄存器操作,所以這里的時鐘線和數(shù)據(jù)線都設(shè)置成輸出管腳,這里封裝了一個emio_init 函數(shù)用于初始化EMIO 引腳;然后初始化OV5640 攝像頭,通過調(diào)用一個封裝好的ov5640_init 函數(shù),先檢查ov5640 是否正確連接,如果檢查通過則調(diào)用sccb_write_reg16 函數(shù),往ov5640 不同的寄存器地址內(nèi)寫入不同的寄存器值。這里OV5640 被配置成DVP(Digital Video Port)輸出接口、1 280×720 分辨率和30FPS(Frame Per Second)。接下來配置VDMA,調(diào)用一個封裝好的run_vdma_frame_buffer 函數(shù),該函數(shù)內(nèi)部包括配置幀緩存地址、寫通道配置、讀通道配置、開啟寫通道和開啟讀通道配置等。VDMA 配置成3 幀圖像緩存功能。初始化視頻時序控制器調(diào)用DisplayInitialize 函數(shù),包括VTC(Video Timing Controller)和動態(tài)時鐘配置。通過Display?SetMode 函數(shù)設(shè)置顯示模式和啟動顯示圖像,采用Display?Start 函數(shù)啟動VTC 開始工作輸出圖像到HDMI 接口。圖6是SDK 主要調(diào)用的函數(shù)截圖。
Fig.5 SDK initialization engineering application process圖5 SDK 初始化工程應(yīng)用程序流程
Fig.6 Functions mainly called by SDK application圖6 SDK 應(yīng)用程序主要調(diào)用的函數(shù)
本設(shè)計使用Alinx 公司的AX7Z020 開發(fā)板作為測試平臺。為測試整個系統(tǒng)工程,方便后期使用,還需將程序固化到Flash 中,以免每次啟動工程都需要通過JTAG 接口燒寫。Zynq 啟動由ARM 主導(dǎo),包括FPGA 程序的加載,啟動階段如下:①階段0。在上電復(fù)位或熱復(fù)位之后,處理器首先執(zhí)行BootRom 中的代碼,此為最初啟動設(shè)置。BootRom存放了一段不可更改的代碼,在非JTAG 模式下執(zhí)行,代碼包含Quad-SPI、SD 的驅(qū)動,還有一個很重要的作用是把階段①的代碼搬運到OCM 中,就是FSBL 代碼(First Stage Boot Loader);②階段①的作用是初始化PS 端配置,也就是在Vivado 工程配置Zynq 核,包括DDR、MIO、SLCR 寄存器。如果有PL 端程序就加載PL 端bitstream,加載bare-metal 應(yīng)用程序到DDR 存儲器,交接給bare-metal 應(yīng)用程序[17]。因此,根據(jù)上面描述,需要再生成一個FSBL 引導(dǎo)程序,完成MIO 分配、時鐘、DDR 控制器、SD、QSPI 控制器初始化工作,再通過啟動模式查找bitstream 配置FPGA,然后搜索應(yīng)用程序加載到DDR,最后交給應(yīng)用程序執(zhí)行。將FSBL 引導(dǎo)程序和整個工程生成的bitstream 文件放在一起,再生成一個boot.bin 文件放到SD 卡的根目錄下,將開發(fā)板設(shè)置為SD卡啟動模式,連上電源和顯示屏,打開電源開關(guān),就能看到如圖7 的測試結(jié)果圖像。
Fig.7 Test results圖7 測試結(jié)果
本文在Zynq-7000 開發(fā)平臺AX7Z020 上使用Xilinx Vivado 開發(fā)工具實現(xiàn)了CMOS OV5640 攝像頭采集數(shù)據(jù),通過HLS 工具實現(xiàn)Sobel 快速邊緣檢測算法,通過Video In to AXI4-Stream 和AXI4-Stream to Video Out 將視頻信號在通用信號格式和AXI4-Stream 專用信號格式之間進行轉(zhuǎn)換,通過VDMA 實現(xiàn)視頻信號的3 幀DDR 緩存功能;通過自定義HDMI 輸出IP 將畫面顯示到顯示屏上,最終通過SDK 應(yīng)用程序控制整個FPGA 工程運行。采用軟硬件協(xié)同的設(shè)計方法使系統(tǒng)更具有可控性和靈活性。同時,在該系統(tǒng)框架上可以很方便地進行圖像處理算法驗證和研究工作。
但是,本文只完成了整個視頻圖像處理數(shù)據(jù)流和控制流的設(shè)計工作,沒有在PS 和PL 硬件之間留出控制接口,因此當(dāng)程序運行起來后無法通過PS 實時控制PL 端。下一步研究工作是在PS 端設(shè)計UI 界面,通過UI 來實時控制PL 端的工作情況,如此可以使得系統(tǒng)針對不同圖像問題執(zhí)行不同的圖像處理算法,并在后續(xù)引入自動圖像評估和加載不同算法等功能。