大俠好,歡迎來到FPGA技術(shù)江湖,江湖偌大,相見即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。
今天給大俠帶來基于FPGA的單目內(nèi)窺鏡定位系統(tǒng)設(shè)計,由于篇幅較長,分三篇。今天帶來第三篇,下篇,話不多說,上貨。
這里也超鏈接前兩篇內(nèi)容。
基于FPGA的單目內(nèi)窺鏡定位系統(tǒng)設(shè)計(上)
基于FPGA的單目內(nèi)窺鏡定位系統(tǒng)設(shè)計(中)
隨著現(xiàn)科技的發(fā)展和社會的進步,信息科技迅速發(fā)展,我們可從互聯(lián)網(wǎng)、電臺等媒體獲取大量信息?,F(xiàn)代信息的存儲、處理和傳輸變得越來越數(shù)字化。在人們的日常生活中,常用的計算機、電視、音響系統(tǒng)、視頻記錄設(shè)備、遠程通訊電子設(shè)備無一不采用電子系統(tǒng)、數(shù)字電路系統(tǒng)。因此,數(shù)字技術(shù)的應(yīng)用越來越廣泛。尤其在通信系統(tǒng)和視頻系統(tǒng)中,數(shù)字系統(tǒng)尤為突出。而隨著FPGA的出世,數(shù)字系統(tǒng)更加受到人們青睞,它為數(shù)字系統(tǒng)的設(shè)計提供更加便捷的通道,使得數(shù)字系統(tǒng)設(shè)計可以芯片小型化,電路規(guī)模大型化,龐大的邏輯資源,可滿足各種數(shù)字系統(tǒng)設(shè)計。
隨著社會的發(fā)展,科學技術(shù)已經(jīng)應(yīng)用于各個領(lǐng)域,尤其是醫(yī)療領(lǐng)域尤為突出。而在醫(yī)療領(lǐng)域中,心臟電信號模擬器手術(shù)輔助儀器發(fā)展迅速。為了訓練經(jīng)驗少的醫(yī)生熟悉心臟手術(shù)的操作過程,而專門開發(fā)心臟信號模擬儀器,讓醫(yī)生迅速掌握心臟手術(shù)操作過程,成為一個經(jīng)驗豐富心臟手術(shù)醫(yī)生。
因此,本文將于FPGA平臺,以圖像處理結(jié)合信號采集原理,實現(xiàn)醫(yī)生在做心臟模擬手術(shù)操作導管的過程中,不需要觀察心臟內(nèi)部情況,即可獲取導管頭在心臟內(nèi)部信息的功能,采用內(nèi)窺鏡攝像頭采集視頻和并對導管頭進行跟蹤定位,信號采集技術(shù)可將采集到的導管頭在心臟內(nèi)部觸碰區(qū)域的信號采集出來送到專業(yè)醫(yī)用儀器,進行心臟3D建模。
本設(shè)計的實現(xiàn)對醫(yī)院培養(yǎng)的經(jīng)驗少的醫(yī)生盡快掌握心臟手術(shù)操作流程很有價值,未來將可以培養(yǎng)更多從事心臟手術(shù)工作的醫(yī)學專業(yè)畢業(yè)的學生或剛剛從事這個行業(yè)的社會醫(yī)生。
第三篇內(nèi)容摘要:本篇會介紹系統(tǒng)調(diào)試與測試以及結(jié)論,包括系統(tǒng)資源性能調(diào)試與分析、系統(tǒng)功能測試等相關(guān)內(nèi)容,還會有VGA的常用分辨率參數(shù)表、整體電路圖、主要程序分享等附錄。
六、系統(tǒng)調(diào)試與測試
本設(shè)計對系統(tǒng)的性能和系統(tǒng)的功能分別進行了測試,性能測試是對FPGA的資源利用情況和運行速度情況進行測試,功能測試有腐蝕算法測試,幀差算法測試,定位功能調(diào)試等。
6.1?系統(tǒng)資源性能調(diào)試與分析
本設(shè)計中,F(xiàn)PGA使用資源如圖6.1所示,組合邏輯資源使用45%,分布式寄存器資源使用23%,總的邏輯宏單元使用52%,存儲器單元使用了15%,一個鎖相環(huán)。EP4CE6F17C8共有2個鎖相環(huán),總邏輯宏單元使用資源小于80%。滿足設(shè)計任務(wù)需求。
圖6.1 EP4CE6F17C8資源使用情況
緩沖模塊穩(wěn)定運行時鐘200M,可用邏輯分析儀SigalTap驗證,驗證結(jié)果如圖6.2和圖6.3所示。
圖6.2 SDRAM傳輸數(shù)據(jù)圖
圖6.3 SDRAM傳輸數(shù)據(jù)圖
結(jié)論:設(shè)計緩沖長度為512,緩沖節(jié)點在256,每次突發(fā)256個數(shù)據(jù),如圖6.2和圖6.3,在數(shù)據(jù)有效信號范圍內(nèi),傳輸數(shù)據(jù)正確。而且工作時鐘在200MHz下運行的,基本能滿足多端點圖像數(shù)據(jù)緩沖需求。
6.2?系統(tǒng)功能測試
腐蝕功能測試:腐蝕前可以看到有許多孤立噪聲點在視頻輸出上,輸出結(jié)果如圖6.4所示,當進行腐蝕算法處理后孤立噪聲點明顯減少,輸出結(jié)果如圖6.5所示。
圖6.4 腐蝕前圖像和幀差結(jié)果
圖6.5 腐蝕后圖像和幀差結(jié)果
圖6.6 幀差結(jié)果
幀差法調(diào)試:調(diào)試過程中遇到了如下一些問題以及對應(yīng)的解決方法。
出現(xiàn)問題:
a. 移屏,整個屏幕的圖像向左方移動一部分,圖像未失真,如圖6.6所示。
b. 幀差結(jié)果出現(xiàn)混亂,如圖6.6所示。
分析問題及解決方法:
a. 移屏問題原因分析,由于SDRAM緩沖讀寫問題,讀上一幀時,還未來得及將所有數(shù)據(jù)讀完,下一幀圖像已經(jīng)來臨,SDRAM寫的優(yōu)先級高于讀優(yōu)先級,所以下一幀數(shù)據(jù)會將上一幀圖像部分數(shù)據(jù)覆蓋導致每一幀的輸出的圖像都會有偏差而出現(xiàn)移屏。因此,解決方法為調(diào)節(jié)復(fù)位延時參數(shù),使得寫入幀和讀出幀保持在先寫入,延時一段時間后在讀出的關(guān)系。
b. 幀差結(jié)果混亂原因分析,一開始使用16位RGB565數(shù)據(jù)做幀差,結(jié)果如圖6.6所示,出現(xiàn)混亂,所以使用合成圖像RGB565做幀差導致出現(xiàn)各個通道顏色對應(yīng)顏色相減溢出到其他通道的情況,所以最終相減的結(jié)果出現(xiàn)混亂。因此解決的方法是對其灰度圖像進行幀差,兩幀圖像相減,再對相減的結(jié)果取絕對值(注意進行減法操作和取絕對值操作時,防止數(shù)據(jù)溢出),即為正確幀差結(jié)果,如圖6.4和6.5所示。觀察這兩張圖像邊緣輪廓明顯,且有明顯的拖尾現(xiàn)象。
圖6.7 運動目標定位
圖6.8 運動目標定位
圖6.9 運動目標定位
功能測試結(jié)果:定位如圖6.7所示,隨著目標物體的運動,運動目標物體有很多坐標點輸出,根據(jù)設(shè)計任務(wù)要求,我們只輸出目標尾端的坐標,下圖右上角為要抓取目標的坐標顯示,可以看到目標所處的位置和輸出的坐標基本符合,圖6.7,圖6.8和圖6.9為運動目標在不同位置的定位結(jié)果。
結(jié)論
本文通過以下幾種手段解決了幀差算法實現(xiàn),導管頭定位問題和系統(tǒng)工作性能問題。
1. 乒乓操作將攝像頭采集到的圖像交替存儲到兩個不同的SDRAM存儲空間,通過SDRAM的緩沖作用,在VGA向SDRAM發(fā)出請求信號時,同時讀出相鄰兩幀的數(shù)據(jù),然后就可做幀差。
2. 導管頭的定位是通過對幀差后的圖像作水平方向和垂直方向的投影,確定出運動目標四條邊界,可確定四個坐標點輸出,但是僅僅有一個坐標點是導管頭的端點,所以計算上邊界與運動物體的交點坐標與左右兩條邊界的距離,判斷導管頭是左上到右下進入攝像頭視覺還是左下到右上進入攝像頭視覺,確定導管兩點坐標輸出,然后再判斷剩余的兩點坐標是否在整張圖像邊界上,確定導管頭坐標輸出。
3. 這個算法設(shè)計更多的使用流水算法,使用移位和拼接運算代替乘法器和除法器,提高系統(tǒng)運行速度,減少資源利用率。
附錄A?VGA的常用分辨率參數(shù)表
附錄B?主要代碼
`include "../sdram_4port_ip/sdram_para.v"
module fd_target_location(
ref_clk,
rst_n,
clk_out,
//cmos interface
CMOS_SCLK, //cmos i2c clock
CMOS_SDAT, //cmos i2c data
CMOS_VSYNC, //cmos vsync
CMOS_HREF, //cmos hsync refrence
CMOS_PCLK, //cmos pxiel clock
CMOS_XCLK, //cmos externl clock
CMOS_DB, //cmos data
//VGA port
VGA_HSYNC, //horizontal sync
VGA_VSYNC, //vertical sync
VGAD, //VGA data
//SDRAM物理端口
S_CLK,
S_CKE,
S_NCS,
S_NCAS,
S_NRAS,
S_NWE,
S_BA,
S_A,
S_DB,
S_DQM
);
input ref_clk;
input rst_n;
output clk_out;
//cmos interface
output CMOS_SCLK; //cmos i2c clock
inout CMOS_SDAT; //cmos i2c data
input CMOS_VSYNC; //cmos vsync
input CMOS_HREF; //cmos hsync refrence
input CMOS_PCLK; //cmos pxiel clock
output CMOS_XCLK; //cmos externl clock
input [7:0] CMOS_DB; //cmos data
//VGA port
output VGA_HSYNC; //horizontal sync
output VGA_VSYNC; //vertical sync
output [15:0] VGAD; //VGA data
//SDRAM物理端口
output S_CLK;
output S_CKE;
output S_NCS;
output S_NCAS;
output S_NRAS;
output S_NWE;
output [`BA-1:0] S_BA;
output [`ROW-1:0] S_A;
inout [`DQ-1:0] S_DB;
output [`DQ/8-1:0] S_DQM;
assign clk_out = clk;
assign S_DQM = 0;
wire vga_clk, camera_clk, clk, sys_rst_n;
// wire rst_dly1, soft_rst_n;
wire soft_rst_0;
wire soft_rst_1;
wire soft_rst_2;
wire soft_rst_3;
wire Config_Done, sdram_init_done;
wire sys_we;
wire [15:0] sys_data_in;
wire frame_valid;
wire lcd_request;
wire [15:0] lcd_data_1;
wire [15:0] lcd_data_2;
wire [15:0] lcd_data;
wire sdram_wrreq;
wire sdram_wrval;
wire [`TOTAL_ADDR-1:0] sdram_wraddr;
wire [`DQ-1:0] sdram_wdata;
wire sdram_wdone;
wire sdram_rdreq;
wire sdram_rdval;
wire [`TOTAL_ADDR-1:0] sdram_rdaddr;
wire [`DQ-1:0] sdram_rdata;
wire sdram_rdone;
wire data_valid;
wire write_done_1;
wire read_done_1;
wire write_done_2;
wire read_done_2;
wire [23:0] waddr_min_1;
wire [23:0] waddr_max_1;
wire bound_valid;
wire [10:0] lcd_xpos;
wire [10:0] lcd_ypos;
wire [10:0] x_pos;
wire [10:0] y_pos;
wire lcd_val;
wire [15:0] lcd_dat;
wire start;
wire [11:0] bcd_x_pos;
wire [11:0] bcd_y_pos;
wire [10:0] target_x_pos;
wire [10:0] target_y_pos;
wire char_en;
wire [3:0] char_data;
reg dval_r1, dval_r2, dval_r3;
dcm dcm(
.clk (ref_clk),
.rst_n (rst_n),
.soft_rst_0 (soft_rst_0),
.soft_rst_1 (soft_rst_1),
.soft_rst_2 (soft_rst_2),
.soft_rst_3 (soft_rst_3),
.clk_c0 (camera_clk), //camera配置模塊時鐘輸出
.clk_c1 (vga_clk), //vga模塊時鐘輸出
.clk_c2 (clk), //sdram控制器時鐘輸出
.clk_c3 (S_CLK) //sdram端口時鐘
);
I2C_AV_Config I2C_AV_Config
(
/*Global clock*/
.iCLK (vga_clk), //25MHz
.iRST_N (soft_rst_0), //Global Reset
.I2C_SCLK (CMOS_SCLK), //I2C CLOCK
.I2C_SDAT (CMOS_SDAT), //I2C DATA
.Config_Done (Config_Done),//Config Done
.LUT_INDEX (), //LUT Index
.I2C_RDATA () //I2C Read Data
);
CMOS_Capture
(
/*Global Clock*/
.iCLK (camera_clk), //13MHz
.iRST_N (soft_rst_2),
/*I2C Initilize Done*/
.Init_Done (Config_Done & sdram_init_done), //Init Done
/*Sensor Interface*/
.CMOS_RST_N (), //cmos work state(5ms delay for sccb config)
.CMOS_PWDN (), //cmos power on
.CMOS_XCLK (CMOS_XCLK), //
.CMOS_PCLK (CMOS_PCLK), //25MHz
.CMOS_iDATA (CMOS_DB), //CMOS Data
.CMOS_VSYNC (CMOS_VSYNC), //L: Vaild
.CMOS_HREF (CMOS_HREF), //H: Vaild
/*Ouput Sensor Data*/
.x_pos (),
.y_pos (),
.CMOS_HREF_pos (),
.CMOS_oCLK (sys_we), //1/2 PCLK
.CMOS_oDATA (sys_data_in), //16Bits RGB
.CMOS_VALID (frame_valid), //Data Enable
.CMOS_FPS_DATA () //cmos fps
);
wire corrode_dval_w1;
wire corrode_data_w1;
wire dilation_dval_w2;
wire dilation_data_w2;
wire dval_w2;
wire data_w2;
wire dval_w3;
wire [15:0] data_w3;
// image_smooth image_smooth(
// .clk (CMOS_PCLK),
// .rst_n (soft_rst_2),
// .dval_i (sys_we),
// .data_i (sys_data_in[7:0]),
// .dval_o (dval_1),
// .data_o (data_1)
// );
// median_filter median_filter(
// .clk (CMOS_PCLK),
// .rst_n (soft_rst_2),
// .dval_i (sys_we),
// .data_i (sys_data_in[7:0]),
// .dval_o (dval_1),
// .data_o (data_1)
// );
image_corrode image_corrode(
.clk (vga_clk),
.rst_n (soft_rst_3),
.dval_i (lcd_val),
.data_i (lcd_dat[0]),
.dval_o (corrode_dval_w1),
.data_o (corrode_data_w1)
);
image_dilation image_dilation(
.clk (vga_clk),
.rst_n (soft_rst_3),
.dval_i (corrode_dval_w1),
.data_i (corrode_data_w1),
.dval_o (dilation_dval_w2),
.data_o (dilation_data_w2)
);
//二值圖像投影
projection projection(
.clk (vga_clk),
.rst_n (soft_rst_3),
.dval_i (lcd_val),
.data_i (lcd_dat[0]),
.x_pos (x_pos),
.y_pos (y_pos),
.target_x_pos (target_x_pos),
.target_y_pos (target_y_pos),
.dval_o (dval_w3),
.data_o (data_w3) //
);
bin_to_bcd u0_bin_to_bcd(.bin(target_x_pos), .bcd(bcd_x_pos));
bin_to_bcd u1_bin_to_bcd(.bin(target_y_pos), .bcd(bcd_y_pos));
char_mac u_char_mac(
.clk (vga_clk),
.rst_n (soft_rst_3),
.start (start),
.bcd_x_pos (bcd_x_pos),
.bcd_y_pos (bcd_y_pos),
.char_en (char_en),
.char_data (char_data)
);
char_disp u_char_disp
(
.clk (vga_clk),
.rst_n (soft_rst_3),
.char_en (char_en),
.char_data (char_data),
.move_x_pos (12'd560),
.move_y_pos (12'd30),
.data_valid_pos (start),
.data_valid (dval_w2), //dval_w2 lcd_val dval_w1 dilation_dval_w2
.x_pos (x_pos),
.y_pos (y_pos),
.data_i ({R[7:3], G[7:2], B[7:3]}), //{R[7:3], G[7:2], B[7:3]} lcd_dat {16{dilation_data_w2}} dilation_data_w2
.data_valid_o (),
.data_o (lcd_data)
);
//------------------------------------------------------
//將yuv轉(zhuǎn)換成rgb輸出
wire [7:0] Y, Cb, Cr;
wire [7:0] R, G, B;
reg [15:0] data_r1;
yuv422_yuv444 yuv422_yuv444(
.clk (vga_clk),
.rst_n (soft_rst_3),
.yuv_capture_en (lcd_request), //ahead 2 clock
.image_data (lcd_data_1), //lcd_data_1
.Y (Y),
.Cb (Cb),
.Cr (Cr)
);
yuv2rgb yuv2rgb(
.clk (vga_clk), //時鐘輸入
.rst (soft_rst_3), //復(fù)位輸入
.y_in (Y), //變換前Y分量輸出
.cb_in (Cb), //變換前Cb分量輸出
.cr_in (Cr), //變換前Cr分量輸出
.ena_in (dval_r1), //待變換數(shù)據(jù)使能,當它為高時,輸入數(shù)據(jù)有效
.R_out (R), //變換后R分量輸出
.G_out (G), //變換后G分量輸出
.B_out (B), //變換后B分量輸出
.ena_out (dval_w2) //變換后數(shù)據(jù)使能輸出
);
always @ (posedge vga_clk or negedge soft_rst_3)
if(soft_rst_3 == 1'b0)
dval_r1 <= 0;
else dval_r1 <= lcd_request;
always @ (posedge vga_clk or negedge soft_rst_3)
if(soft_rst_3 == 1'b0)
dval_r2 <= 0;
else dval_r2 <= dval_w2;
assign start = ~dval_r2 & dval_w2;
// Virtual_Camera Virtual_Camera(
// .clk (vga_clk),
// .rst_n (soft_rst_2),
// .sdram_init_done (sdram_init_done),
// .dval (sys_we),
// .data (sys_data_in)
// );
switch_in switch_in(
.clk (clk),
.rst_n (soft_rst_1),
.frame_done (write_done_1),
.waddr_min_1 (waddr_min_1),
.waddr_max_1 (waddr_max_1)
);
switch_out switch_out(
.clk (vga_clk),
.rst_n (soft_rst_3),
.request (lcd_request),
.x_pos_i (lcd_xpos),
.y_pos_i (lcd_ypos),
.x_pos (x_pos),
.y_pos (y_pos),
.start_o (),
.lcd_data_1 (lcd_data_1),
.lcd_data_2 (lcd_data_2),
.lcd_val (lcd_val),
.lcd_data (lcd_dat) //lcd_data
);
async_4fifo async_4fifo(
.clk (clk),
.rst_n (soft_rst_1),
.sdram_init_done (sdram_init_done), //sdram初始化完成信號
/*用戶接口*/
/*寫用戶1接口*/
.clk_write_1 (CMOS_PCLK), //vga_clk, CMOS_PCLK
.wrreq_1 (sys_we), //sys_we dval_1
.wdata_1 (sys_data_in), //sys_data_in {8'd0, data_1}
.write_done_1 (write_done_1),
/*參數(shù)設(shè)置*/
.waddr_min_1 (waddr_min_1), //24'd0
.waddr_max_1 (waddr_max_1), //24'd307200
.wr_length_1 (9'd256), //,這個是緩沖節(jié)點
/*讀用戶1接口*/
.clk_read_1 (vga_clk), //vga_clk
.rdreq_1 (lcd_request), //lcd_request
.rdata_1 (lcd_data_1), //lcd_data lcd_data_1
.read_done_1 (),
.data_valid_1 (data_valid), //sdram讀端口同步信號
/*參數(shù)設(shè)置*/
.raddr_min_1 (24'd0),
.raddr_max_1 (24'd307200),
.rd_length_1 (9'd256), //,這個是緩沖節(jié)點
/*寫用戶2接口*/
.clk_write_2 (CMOS_PCLK), //vga_clk, CMOS_PCLK
.wrreq_2 (0), //sys_we
.wdata_2 (0), //sys_data_in
.write_done_2 (),
/*參數(shù)設(shè)置*/
.waddr_min_2 (24'd0), //24'd307200
.waddr_max_2 (24'd0), //24'd614400
.wr_length_2 (9'd256), //必須添加很重要,這個是緩沖節(jié)點
/*讀用戶2接口*/
.clk_read_2 (vga_clk),
.rdreq_2 (lcd_request), //lcd_request
.rdata_2 (lcd_data_2), //lcd_data lcd_data_2
.read_done_2 (),
.data_valid_2 (data_valid), //sdram讀端口同步信號 data_valid
/*參數(shù)設(shè)置*/
.raddr_min_2 (24'd307200), //24'd307200
.raddr_max_2 (24'd614400), //24'd614400
.rd_length_2 (9'd256), //必須添加很重要,這個是緩沖節(jié)點
/*寫SDRAM端口*/
.sdram_wrreq (sdram_wrreq),
.sdram_wrval (sdram_wrval),
.sdram_wraddr (sdram_wraddr),
.sdram_wdata (sdram_wdata),
.sdram_wdone (sdram_wdone),
/*讀SDRAM端口*/
.sdram_rdreq (sdram_rdreq),
.sdram_rdval (sdram_rdval),
.sdram_rdaddr (sdram_rdaddr),
.sdram_rdata (sdram_rdata),
.sdram_rdone (sdram_rdone)
);
lsm_sdram lsm_sdram(
/*全局變量*/
.clk (clk),
.rst_n (soft_rst_1),
.sdram_init_done (sdram_init_done),
/*寫SDRAM端口*/
.sdram_wrreq (sdram_wrreq),
.sdram_wrval (sdram_wrval),
.sdram_wraddr (sdram_wraddr),
.sdram_wdata (sdram_wdata),
.sdram_wdone (sdram_wdone),
/*讀SDRAM端口*/
.sdram_rdreq (sdram_rdreq),
.sdram_rdval (sdram_rdval),
.sdram_rdaddr (sdram_rdaddr),
.sdram_rdata (sdram_rdata),
.sdram_rdone (sdram_rdone),
/*SDRAM物理端口*/
.sdram_clk (),
.sdram_cke (S_CKE),
.sdram_cs_n (S_NCS),
.sdram_cas_n (S_NCAS),
.sdram_ras_n (S_NRAS),
.sdram_we_n (S_NWE),
.sdram_ba (S_BA),
.sdram_a (S_A),
.sdram_dq (S_DB),
.sdram_dqm ()
);
lcd_top lcd_top
(
//global clock
.clk (vga_clk), //system clock
.rst_n (soft_rst_3), //sync reset
//lcd interface
.lcd_dclk (), //lcd pixel clock
.lcd_blank (), //lcd blank
.lcd_sync (), //lcd sync
.lcd_hs (VGA_HSYNC), //lcd horizontal sync
.lcd_vs (VGA_VSYNC), //lcd vertical sync
.lcd_en (), //lcd display enable
.lcd_rgb (VGAD), //lcd display data
//user interface
.lcd_request (lcd_request), //lcd data request
.lcd_framesync (data_valid), //lcd frame sync
.lcd_pos (),
.lcd_xpos (lcd_xpos), //lcd horizontal coordinate
.lcd_ypos (lcd_ypos), //lcd vertical coordinate
.lcd_data (lcd_data) //lcd data
);
endmodule
本篇到此結(jié)束,各位大俠有緣再見!