網(wǎng)校網(wǎng)站建設(shè)方案優(yōu)化設(shè)計方法
文章目錄
- 一、前言
- 二、FPGA實現(xiàn)三行緩存的架構(gòu)
- 三、Verilog代碼實現(xiàn)
- 四、仿真驗證
- 五、輸入圖像數(shù)據(jù)進行仿真驗證
一、前言
??在 FPGA 做圖像處理時,行緩存是一個非常重要的一個步驟,因為圖像輸入還有輸出都是一行一行進行的,即處理完一行后再處理下一行。行緩存可以存儲當前行和前一行的數(shù)據(jù)以及多行的數(shù)據(jù),使得在處理當前行時能夠方便地訪問周圍像素。許多圖像處理的算法都需要幾行的圖像數(shù)據(jù)進行處理,因此行緩存是非常重要的,本文實現(xiàn)三行緩存,多行緩存的思想也是一致的。
二、FPGA實現(xiàn)三行緩存的架構(gòu)
??由于圖像數(shù)據(jù)一般都是從上到下從左到右一個一個輸入進來,因此我們優(yōu)先考慮使用FIFO,先進先出。按照一般想法,我們只需要三個FIFO,每個FIFO存儲一行數(shù)據(jù)即可實現(xiàn)三行緩存,這里可以節(jié)省資源只使用兩個FIFO實現(xiàn),具體實現(xiàn)框框架如下:
??開始時,圖像數(shù)據(jù)的第0行寫入到FIFO1中,圖像數(shù)據(jù)的第1行寫入到FIFO2中。
??當?shù)?行數(shù)據(jù)到來時寫入到FIFO2中,同時輸出寫入的數(shù)據(jù)作為第二行;同時讀出FIFO2中的數(shù)據(jù)寫入到FIFO1中,并輸出作為第一行,同時讀出FIFO1中的數(shù)據(jù)輸出作為第0行。
??同理,當?shù)谌袛?shù)據(jù)來臨時寫入到FIFO2中,同時輸出寫入數(shù)據(jù)作為第二行,再同時讀出FIFO2中的數(shù)據(jù)寫入到FIFO1中并輸出作為第一行,同時讀出FIFO2中的數(shù)據(jù)輸出作為第0行。后面的行以此類推。
三、Verilog代碼實現(xiàn)
??先看輸入接口,輸入為像素數(shù)據(jù)和有效信號,輸出為三行數(shù)據(jù)以及有效信號。
input sys_clk ,input sys_rst ,input [23:0] i_img_data ,input i_img_data_valid ,output [23:0] o_img_data_1line ,output [23:0] o_img_data_2line ,output [23:0] o_img_data_3line ,output o_img_data_valid
??再次例化兩個FIFO,位寬就為一個像素位寬,深度為一行中最多的像素數(shù)量。
img_line_buffer_fifo u0_img_line_buffer_fifo (.clk (sys_clk ), // input wire clk.srst (sys_rst ), // input wire srst.din (fifo1_wr_data ), // input wire [23 : 0] din.wr_en(fifo1_wr_en ), // input wire wr_en.rd_en(rd_en ), // input wire rd_en.dout (fifo1_q ), // output wire [23 : 0] dout.full (), // output wire full.empty() // output wire empty
);img_line_buffer_fifo u1_img_line_buffer_fifo (.clk (sys_clk ), // input wire clk.srst (sys_rst ), // input wire srst.din (fifo2_wr_data ), // input wire [23 : 0] din.wr_en(fifo2_wr_en ), // input wire wr_en.rd_en(rd_en ), // input wire rd_en.dout (fifo2_q ), // output wire [23 : 0] dout.full (), // output wire full.empty() // output wire empty
);
??然后根據(jù)架構(gòu)圖編寫出剩下的代碼,編寫仿真代碼。
四、仿真驗證
??仿真我們先設(shè)置圖像寬度為50*50,這樣仿真可以跑快一點,然后寫入數(shù)據(jù)流為每次都是0-49循環(huán)。就像一幅圖像的第0行數(shù)據(jù)是0-49,第1行的數(shù)據(jù)也是0-49,每一行的數(shù)據(jù)都是0-49。按照想法,我們每次輸出的數(shù)據(jù)就是前三行的像素,也就是3行的 0-49數(shù)據(jù),仿真代碼如下:
`timescale 1ns / 1psmodule tb_img_3line_buffer();reg sys_clk ;
reg sys_rst ;
reg i_img_data_valid ;
reg [23:0] i_img_data ;
reg [12:0] cnt ;
wire [23:0] o_img_data_1line ;
wire [23:0] o_img_data_2line ;
wire [23:0] o_img_data_3line ;
wire o_img_data_valid ;initial beginsys_clk =0;sys_rst = 1;i_img_data_valid = 0;i_img_data = 'd0;#200;sys_rst = 0;
endalways #5 sys_clk = ~sys_clk;always @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data_valid <= 1'b0;else if(cnt == 49)i_img_data_valid <= 1'b0;elsei_img_data_valid <= 1'b1;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)cnt <= 'd0;else if(cnt == 49)cnt <= 'd0;else if(i_img_data_valid == 1'b1)cnt <= cnt + 1'b1;elsecnt <= cnt;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data <= 'd0;else if(i_img_data == 49)i_img_data <= 'd0;else if(i_img_data_valid == 1'b1)i_img_data <= i_img_data + 1'b1;elsei_img_data <= i_img_data;
endimg_3line_buffer#(.IMG_WIDTH ( 50 ),.IMG_HEIGHT ( 50 )
)u_img_3line_buffer(.sys_clk ( sys_clk ),.sys_rst ( sys_rst ),.i_img_data ( i_img_data ),.i_img_data_valid ( i_img_data_valid ),.o_img_data_1line ( o_img_data_1line ),.o_img_data_2line ( o_img_data_2line ),.o_img_data_3line ( o_img_data_3line ),.o_img_data_valid ( o_img_data_valid )
);endmodule
??運行仿真
??可以看到寫入的每一行數(shù)據(jù)都是0-49,寫入兩行后,開始輸出數(shù)據(jù)。
??我們可以看到輸出的三行數(shù)據(jù)都是0-49的數(shù)據(jù)。符合預(yù)期。我們修改一下仿真代碼,寫入2500個數(shù)據(jù),對應(yīng)50*50的圖像大小,數(shù)據(jù)為0-2499,這樣第0行的數(shù)據(jù)就是0-49,第1行的數(shù)據(jù)就是50-99,第2行的數(shù)據(jù)就是100-149,第3行的數(shù)據(jù)就是150-199。輸出的數(shù)據(jù)就應(yīng)該是(0,50,100),(1,51,101)以此類推,仿真代碼如下:
`timescale 1ns / 1psmodule tb_img_3line_buffer();reg sys_clk ;
reg sys_rst ;
reg i_img_data_valid ;
reg [23:0] i_img_data ;
reg [12:0] cnt ;
wire [23:0] o_img_data_1line ;
wire [23:0] o_img_data_2line ;
wire [23:0] o_img_data_3line ;
wire o_img_data_valid ;initial beginsys_clk =0;sys_rst = 1;i_img_data_valid = 0;i_img_data = 'd0;#200;sys_rst = 0;
endalways #5 sys_clk = ~sys_clk;always @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data_valid <= 1'b0;else if(cnt == 2499)i_img_data_valid <= 1'b0;elsei_img_data_valid <= 1'b1;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)cnt <= 'd0;else if(cnt == 2499)cnt <= 'd0;else if(i_img_data_valid == 1'b1)cnt <= cnt + 1'b1;elsecnt <= cnt;
endalways @(posedge sys_clk) beginif(sys_rst == 1'b1)i_img_data <= 'd0;else if(i_img_data == 2499)i_img_data <= 'd0;else if(i_img_data_valid == 1'b1)i_img_data <= i_img_data + 1'b1;elsei_img_data <= i_img_data;
endimg_3line_buffer#(.IMG_WIDTH ( 50 ),.IMG_HEIGHT ( 50 )
)u_img_3line_buffer(.sys_clk ( sys_clk ),.sys_rst ( sys_rst ),.i_img_data ( i_img_data ),.i_img_data_valid ( i_img_data_valid ),.o_img_data_1line ( o_img_data_1line ),.o_img_data_2line ( o_img_data_2line ),.o_img_data_3line ( o_img_data_3line ),.o_img_data_valid ( o_img_data_valid )
);endmodule
??運行仿真
??驗證完成和預(yù)期一致,后續(xù)一些圖像處理算法需要用到這個行緩存。
五、輸入圖像數(shù)據(jù)進行仿真驗證
??現(xiàn)在我們在仿真中輸入一張圖片,然后通過三行緩存輸出,每次只取出第一行的數(shù)據(jù)寫入到新的圖片中:
??可以看出輸出的圖像和輸入圖像一模一樣,文件大小也是一模一樣,因此三行緩存是沒問題的。