本篇主要針對牟新剛編著《基於FPGA的數字圖像處理及應用》第六章第五節中直方圖統計相關類容進行總結,包括代碼實現及算法
基於Modelsim的仿真。書讀百遍,其意自現。 2020-03-09 22:16:07緩存
設計難點:異步
(1)統計工做至少要等到當前圖像「流過」以後才能完成。此限制決定了咱們不可能對統計工做進行流水統計和輸出。ide
(2)必須對前期的統計結果進行緩存。測試
(3)在下一次統計前須要將緩存結果清零。優化
在直方圖統計中,咱們通常選擇片內雙口RAM做爲緩存存儲器。對於8位的深度圖來講,統計結果的數據量並不大,所以選擇片內ui
RAM。此外,一方面統計模塊須要與其餘時序進行配合,所以需提供雙邊讀寫接口;另外一方面,統計過程當中須要地址信息,所以選擇spa
RAM形式的存儲器。接下來的工做就是肯定雙口RAM的參數,主要包括數據位寬及地址位寬。假定輸入圖像寬度爲IW,高度爲IH,數據命令行
位寬度爲DW。那麼待統計的像素總數爲PixelTotal = IW * IH,像素灰度值的理論最大值爲PixelMax=2DW-1。設計
雙口RAM的統計地址輸入端爲輸入像素值,很明顯,這個數據範圍爲0~2DW-1,所以RAM的地址位寬最少爲DW,即 AWDPRAM ≥ DW。
雙口RAM的數據輸出端爲輸入統計值,很明顯,這個數據範圍爲0~PixelTotal,所以RAM的地址位寬最少爲log2(PixelTotal)。即DWDPRAM ≥ log2(PixelTotal)。
例如要對圖像分辨率爲640 x 512位寬爲8位的圖像進行直方圖統計,則有
AWDPRAM ≥ 8
DWDPRAM ≥ log2(PixelTotal) = log2(640x512) ≈19。
一般狀況下會將兩個參數取爲2的整次冪,即AWDPRAM = 8, DWDPRAM =32。
直方圖統計步驟以下:
(1)將當前統計值讀出,加1後從新寫入RAM。
(2)重複以上步驟,直至當前圖像統計完畢。
(3)在下一副圖像到來以前將結果讀出。
(4)讀出以後對RAM內容進行清零。
所以以下圖所示,要完成直方圖統計,須要至少設計三個電路:統計電路,讀出電路,讀出電路和清零電路。
1.統計電路
在實際的圖像中,連續的像素點灰度值爲相同值的狀況很是常見,若是每來一個像素都對雙口RAM進行一次尋址和寫操做,顯然下降了統計效率而提升了功耗。書中給出了一種優化的統計方法:採用一個相同灰度值計數器進行優化,
其中:
(1)DPRAM:存放統計結果。分爲A口和B口,A口負責統計結果寫入,不輸出。B口負責統計結果讀出和清零,無輸入。
(2)CNT: 相同像素計數器。負責對連續相同灰度值的像素進行計數,復位值爲1。
(3)ADD(+):統計值加法器。對當前統計值和新的統計值進行加法運算,從新寫入RAM。
(4)B_ADDR MUX: B口地址mux,很明顯,B口在統計階段須要完成讀出前一個統計值和清零的分時操做。所以須要一個mux對讀出地址和清零地址進行選通。
(5)reg:將輸入數據打兩拍以確保讀出的是當前的統計值。
統計原理以下:
當前灰度值的統計值由B口讀出,與相同灰度值計數器進行相加後從新寫入RAM。CNT會不斷檢測當前像素和前一個像素是否一致,若不一致,則重置爲1,實現統計值加1目的;若一致,則計數器加1,直到不一致以後將一致的總數
寫入RAM,並在每一行圖像的最後一個像素統一執行一次寫入操做(沒明白啥意思),這樣大大減小讀寫RAM操做。
下面幾個關鍵信號的設計電路來講明統計電路的工做原理。首先將輸入信號din,輸入有效dvalid打兩拍,分別爲din_r,din_r2及dvalid_r,dvalid_r2。
(1)inc_en
此信號負責遞增計數器的遞增使能。當前待統計數據din_r2有效,且與前一個已經統計完成的數據din_r相同時,將遞增計數器加1。不然計數器會復位到1。
(2)rst_cnt
此信號爲遞增計數器的復位信號。除了當前待統計灰度值與上一個統計過的灰度值不一樣的狀況下會復位計數器,第一個有效數據到來時也會復位遞增計數器,爲新的一輪統計工做作準備。
(3)we_a
此信號爲DPRAM寫入信號,也是分爲兩種狀況:若當前待統計灰度值與以前待統計值不一樣。則直接寫入RAM。不然,就一直累加到數據無效時統一寫入RAM。
(4)count_en
此信號爲統計使能,很明顯,在統計階段此信號須要一直保持有效,統計完成後(也即當前圖像遍歷完畢),在讀出和清零階段,須要將此信號失能,這是因爲B口在此階段須要讀出和清零地址。
此信號的產生能夠經過對圖像進行行計數來實現,當到達一副圖像的高度時,失能信號。新的行同步到來時使能信號。
2.讀出電路設計
首先書中統計讀出方法是順序讀出,即灰度值爲0的統計值首先讀出,其次是灰度值爲1的統計值,最後是灰度值爲255的統計值輸出。
讀出和清零操做並不必定是在統計完成以後當即進行的,能夠根據須要由外部時序控制,輸入讀出請求。固然在統計階段,模塊是不容許讀出的,此時讀出電路處於復位狀態。在讀出階段,需設計
讀出像素計數器對讀出時序進行控制。
只有當計數完成,而且外部時序申請讀出時,輸出地址纔會進行遞增。不然會被鉗位到0。當一次讀出完成以後此地址發生器復位,也就是count_en會從新使能,直到下一次統計完成。
3.清零電路設計
書中給出反相清零的方法,即在讀出時鐘的下一個時鐘進行清零。所以每一個像素的統計數據輸出和清零操做均需佔用1個時鐘,奇數時鐘輸出,偶數時鐘清零。
代碼的部分參照書中的代碼實現,並與前面灰度圖像生成代碼進行整合編譯仿真。惟一須要特別注意的是在實例化DPRAM IP核時,輸出端口切記不要緩存(添加寄存器輸出)。相應整理後的代碼以下:
`timescale 1ps/1ps //==============================================================================// //FileName: histogram_2d.v //Date: 2020-02-29 //==============================================================================// module histogram_2d( rst_n, clk, din_valid, //輸入有效 din, //輸入待統計的數據 dout, //統計輸出 vsync, //輸入場同步 dout_valid, //輸出有效 int_flag, //中斷輸出 rdyOutput, //數據讀出請求 dout_clk //數據輸出時鐘 ); //模塊入口參數 parameter DW = 14; //數據位寬 parameter IH = 512; //圖像高度 parameter IW = 640; //圖像寬度 parameter TW = 32; //直方圖統計數據位寬 localparam TOTAL_CNT = IW * IH; //像素總數 localparam HALF_WIDTH = (TW >> 1); //將32位的數據位寬拆分爲高低16位 //輸入輸出聲明 input rst_n; input clk; input din_valid; input [DW-1:0] din; input rdyOutput; //output wire [HALF_WIDTH:0] dout; output wire [TW-1:0] dout; input vsync; output reg dout_valid; output reg int_flag; output dout_clk; //變量聲明 reg vsync_r; reg dvalid_r; reg dvalid_r2; reg [DW-1:0] din_r; reg [DW-1:0] din_r2; wire hsync_fall; wire hsync_rise; reg [9:0] hsync_count; reg count_en; wire [DW-1:0] mux_addr_b; wire [DW-1:0] mux_addr_b2; wire [TW-1:0] q_a; wire [TW-1:0] q_b; reg [TW-1:0] counter; wire [TW-1:0] count_value; wire rst_cnt; //統計計數器復位信號 wire inc_en; //遞增使能信號 //DPRAM 信號 wire we_a; wire we_b; wire we_b_l; reg we_b_h; wire [DW-1:0] addr_a; //中斷寄存器 reg int_r; wire [DW-1:0] clr_addr; //清零地址 reg [DW-1:0] clr_addr_r; reg [DW:0] out_pixel; //輸出計數 reg count_all; //統計完成信號 //reg count_en_r; reg count_en_r; reg [TW-1:0] hist_cnt; //直方圖統計累加寄存器 wire rstOutput; //讀出電路復位信號 wire [TW-1:0] dataTmp2; wire clr_flag; //全局清零 //將輸入數據打兩拍 always@(posedge clk or negedge rst_n)begin if(((~(rst_n))) == 1'b1) begin vsync_r <= #1 1'b0; dvalid_r <= #1 1'b0; dvalid_r2 <= #1 1'b0; din_r <= #1 {DW{1'b0}}; din_r2 <= #1 {DW{1'b0}}; end else begin vsync_r <= #1 vsync; dvalid_r <= #1 din_valid; dvalid_r2 <= #1 dvalid_r; din_r <= #1 din; din_r2 <= #1 din_r; end end //輸入行同步計數,肯定統計的開始和結束時刻 assign #1 hsync_fall = dvalid_r & (~(din_valid)); assign #1 hsync_rise = (~(dvalid_r)) & din_valid; always@(posedge clk or negedge rst_n)begin if(((~(rst_n))) == 1'b1) hsync_count <= #1 {10{1'b0}}; else begin if(vsync_r == 1'b1) hsync_count <= #1 {10{1'b0}}; else if(hsync_fall == 1'b1) hsync_count <= hsync_count + 10'b1; end end //一幀圖像結束後中止統計 下一幀圖像到來時開始計數 always@(posedge clk or negedge rst_n)begin if(((~(rst_n))) == 1'b1) count_en <= #1 1'b0; else begin if(hsync_count >= IH) count_en <= #1 1'b0; else if(hsync_rise == 1'b1) count_en <= #1 1'b1; else count_en <= #1 count_en; end end assign mux_addr_b = ((count_en == 1'b1)) ? din_r : clr_addr; assign mux_addr_b2 = ((count_en == 1'b1)) ? din_r : clr_addr_r; //統計遞增計數器 always@(posedge clk)begin if(rst_cnt == 1'b1) counter <= #1 {{TW-1{1'b0}},1'b1}; //復位值爲1 else if(inc_en == 1'b1) counter <= #1 counter + {{TW-1{1'b0}},1'b1}; else counter <= #1 counter; end assign #1 rst_cnt = ((din_r != din_r2) | ((dvalid_r2 == 1'b1) & (dvalid_r == 1'b0))) ? 1'b1 : 1'b0; assign #1 inc_en = (((din_r == din_r2) & (dvalid_r2 == 1'b1))) ? 1'b1 : 1'b0; assign #1 we_a = ((((din_r != din_r2) & (dvalid_r2 == 1'b1)) |((dvalid_r2 == 1'b1) & (dvalid_r == 1'b0)))) ? 1'b1 : 1'b0; assign #1 count_value = ((count_en == 1'b1)) ? counter+q_b : {TW{1'b0}}; assign #1 addr_a = din_r2; //直方圖存儲器 分高16位和低16位分別存儲 hist_buffer dpram_bin_l( .address_a(addr_a), //輸入地址爲像素灰度值 .address_b(mux_addr_b), //讀出和清零地址 .clock(clk), //同步時鐘 .data_a(count_value[HALF_WIDTH-1:0]), //當前計數值 .data_b({HALF_WIDTH{1'b0}}), //清零數據 .wren_a(we_a), .wren_b(we_b_l), .q_a(q_a[HALF_WIDTH-1:0]), .q_b(q_b[HALF_WIDTH-1:0]) ); hist_buffer dpram_bin_h( .address_a(addr_a), .address_b(mux_addr_b2), .clock(clk), .data_a(count_value[TW-1:HALF_WIDTH]), .data_b({HALF_WIDTH{1'b0}}), .wren_a(we_a), .wren_b(we_b_h), .q_a(q_a[TW-1:HALF_WIDTH]), .q_b(q_b[TW-1:HALF_WIDTH]) ); always@(posedge clk or negedge rst_n)begin if(((~(rst_n))) == 1'b1) count_en_r <= #1 1'b0; else count_en_r <= #1 count_en; end //讀出電路邏輯,計數時不能輸出,讀出請求時才輸出 assign rstOutput = count_en_r | (~(rdyOutput)); //輸出像素計數 always@(posedge clk)begin if(rstOutput == 1'b1) out_pixel <= {DW+1{1'b0}}; else begin if((~count_all) == 1'b1) begin if(out_pixel == (((2 ** (DW + 1)) - 1))) out_pixel <= #1 {DW+1{1'b0}}; //輸出完畢 else out_pixel <= #1 out_pixel + 1'b1; end end end //統計結束信號 always@(posedge clk)begin //count_all_r <= (~rstOutput); we_b_h <= we_b_l; clr_addr_r <= clr_addr; if(out_pixel == (((2 ** (DW + 1)) - 1))) count_all <= #1 1'b1; else if(count_en == 1'b1) count_all <= #1 1'b0; end //全局清零信號 assign clr_flag = vsync; //中斷輸出 信號讀出操做完成 always@(posedge clk or negedge rst_n)begin if((~(rst_n)) == 1'b1) begin int_flag <= 1'b1; int_r <= 1'b1; end else begin int_flag <= #1 int_r; if(clr_flag == 1'b1) int_r <= #1 1'b1; else if(out_pixel >= (((2 ** (DW + 1)) - 1))) int_r <= #1 1'b0; end end assign we_b_l = (((out_pixel[0] == 1'b1) & (count_all == 1'b0))) ? 1'b1 : 1'b0; //清零地址,與讀出地址反相 assign clr_addr = out_pixel[DW:1]; wire dout_valid_temp; wire [HALF_WIDTH-1:0] dout_temp; always@(posedge clk or negedge rst_n)begin if((~(rst_n)) == 1'b1) begin //dout <= {HALF_WIDTH{1'b0}}; dout_valid <= 1'b0; end else begin //dout <= #1 dout_temp; dout_valid <= #1 dout_valid_temp; end end assign dout_temp = (we_b_l == 1'b1) ? q_b[HALF_WIDTH-1:0] : q_b[TW-1:HALF_WIDTH]; assign dout_valid_temp = we_b_h | we_b_l; //輸出使能 assign dout_clk = (dout_valid) ? we_b_h : 1'b0; assign dout = q_b; endmodule
頂層代碼設計以下:
1 `timescale 1ps/1ps 2 3 //===========================================================================================// 4 //FileName: histogram.v 5 //Date: 2020-03-02 6 //===========================================================================================// 7 8 9 module histogram( 10 RSTn, //全局復位 11 CLOCK, //系統時鐘 12 13 IMG_CLK, //像素時鐘 14 IMG_DVD, //像素值 15 IMG_DVSYN, //輸入場信號 16 IMG_DHSYN, //輸入數據有效信號 17 HIST_DAT, //輸出直方圖統計數據 18 HIST_VALID, //輸出直方圖統計有效 19 HIST_RDY, //數據讀出請求 20 HIST_INT, //數據中斷輸出 21 HIST_CLK //數據輸出時鐘 22 23 ); 24 25 /*image parameter*/ 26 parameter iw = 640; //image width 27 parameter ih = 512; //image height 28 parameter trig_value = 400; //250 29 parameter tw = 32; //直方圖統計數據位寬 30 31 localparam half_width = (tw >> 1); //將32位的數據位寬拆分爲高低16位 32 33 /*data width*/ 34 parameter dvd_dw = 8; //image source data width 35 parameter dvd_chn = 3; //channel of the dvd data: when 3 it's rgb or 4:4:YCbCr 36 parameter local_dw = dvd_dw * dvd_chn; //local algorithem process data width 37 parameter cmd_dw = dvd_dw * dvd_chn; //local algorithem process data width 38 39 //Port Declared 40 input RSTn; 41 input CLOCK; 42 input IMG_CLK; 43 input [dvd_dw-1:0] IMG_DVD; 44 input IMG_DVSYN; 45 input IMG_DHSYN; 46 output [tw-1:0] HIST_DAT; 47 output HIST_VALID; 48 input HIST_RDY; 49 output HIST_INT; 50 output HIST_CLK; 51 52 //Variable Declared 53 wire GRAY_CLK; 54 wire GRAY_VSYNC; 55 wire GRAY_DVALID; 56 wire [dvd_dw-1:0] Y_DAT; 57 wire [dvd_dw-1:0] Cb_DAT; 58 wire [dvd_dw-1:0] Cr_DAT; 59 60 wire [local_dw-1:0] RGB_DAT; 61 wire RGB_DVALID; 62 wire RGB_VSYNC; 63 64 video_cap video_cap_inst( 65 .reset_l(RSTn), //異步復位信號 66 .DVD(IMG_DVD), //輸入視頻流 67 .DVSYN(IMG_DVSYN), //輸入場同步信號 68 .DHSYN(IMG_DHSYN), //輸入行同步 69 .DVCLK(IMG_CLK), //輸入DV時鐘 70 .cap_dat(RGB_DAT), //輸出RGB通道像素流,24位 71 .cap_dvalid(RGB_DVALID), //輸出數據有效 72 .cap_vsync(RGB_VSYNC), //輸出場同步 73 .cap_clk(CLOCK), //本地邏輯時鐘 74 .img_en(), 75 .cmd_rdy(), //命令行準備好,表明能夠讀取 76 .cmd_rdat(), //命令行數據輸出 77 .cmd_rdreq() //命令行讀取請求 78 ); 79 80 defparam video_cap_inst.DW_DVD = dvd_dw; 81 defparam video_cap_inst.DW_LOCAL = local_dw; 82 defparam video_cap_inst.DW_CMD = cmd_dw; 83 defparam video_cap_inst.DVD_CHN = dvd_chn; 84 defparam video_cap_inst.TRIG_VALUE = trig_value; 85 defparam video_cap_inst.IW = iw; 86 defparam video_cap_inst.IH = ih; 87 88 RGB2YCrCb RGB2YCrCb_Inst( 89 .RESET(RSTn), //異步復位信號 90 91 .RGB_CLK(CLOCK), //輸入像素時鐘 92 .RGB_VSYNC(RGB_VSYNC), //輸入場同步信號 93 .RGB_DVALID(RGB_DVALID), //輸入數據有信號 94 .RGB_DAT(RGB_DAT), //輸入RGB通道像素流,24位 95 96 .YCbCr_CLK(GRAY_CLK), //輸出像素時鐘 97 .YCbCr_VSYNC(GRAY_VSYNC), //輸出場同步信號 98 .YCbCr_DVALID(GRAY_DVALID), //輸出數據有效信號 99 .Y_DAT(Y_DAT), //輸出Y份量 100 .Cb_DAT(Cb_DAT), //輸出Cb份量 101 .Cr_DAT(Cr_DAT) //輸出Cr份量 102 ); 103 104 defparam RGB2YCrCb_Inst.RGB_DW = local_dw; 105 defparam RGB2YCrCb_Inst.YCbCr_DW = dvd_dw; 106 107 histogram_2d histogram_2d_inst( 108 .rst_n(RSTn), 109 .clk(GRAY_CLK), 110 .din_valid(GRAY_DVALID), //輸入有效 111 .din(Y_DAT), //輸入待統計的數據 112 .dout(HIST_DAT), //統計輸出 113 .vsync(GRAY_VSYNC), //輸入場同步 114 .dout_valid(HIST_VALID), //輸出有效 115 .int_flag(HIST_INT), //中斷輸出 116 .rdyOutput(HIST_RDY), //數據讀出請求 117 .dout_clk(HIST_CLK) 118 ); 119 120 defparam histogram_2d_inst.DW = dvd_dw; 121 defparam histogram_2d_inst.IH = ih; 122 defparam histogram_2d_inst.IW = iw; 123 defparam histogram_2d_inst.TW = tw; 124 125 endmodule
用於測試仿真的文件以下:
1 `timescale 1ps/1ps 2 3 module histogram_tb; 4 5 6 /*image para*/ 7 parameter iw = 640; //image width 8 parameter ih = 512; //image height 9 parameter trig_value = 400; //250 10 11 /*video parameter*/ 12 parameter h_total = 2000; 13 parameter v_total = 600; 14 parameter sync_b = 5; 15 parameter sync_e = 55; 16 parameter vld_b = 65; 17 18 parameter clk_freq = 72; 19 20 /*data width*/ 21 parameter dvd_dw = 8; //image source data width 22 parameter dvd_chn = 3; //channel of the dvd data: when 3 it's rgb or 4:4:YCbCr 23 parameter local_dw = dvd_dw * dvd_chn; //local algorithem process data width 24 parameter cmd_dw = dvd_dw * dvd_chn; //local algorithem process data width 25 26 27 parameter hist_dw = 32 >> 1; 28 29 /*test module enable*/ 30 parameter cap_en = 1; 31 32 /*signal group*/ 33 reg pixel_clk = 1'b0; 34 reg reset_l; 35 reg [3:0] src_sel; 36 37 38 /*input dv group*/ 39 wire dv_clk; 40 wire dvsyn; 41 wire dhsyn; 42 wire [dvd_dw-1:0] dvd; 43 44 wire [31:0] HIST_DAT; 45 wire HIST_VALID; 46 wire HIST_INT; 47 wire HIST_CLK; 48 49 /*dvd source data generated for simulation*/ 50 image_src //#(iw*dvd_chn, ih+1, dvd_dw, h_total, v_total, sync_b, sync_e, vld_b) 51 u1( 52 .clk(pixel_clk), 53 .reset_l(reset_l), 54 .src_sel(src_sel), 55 .test_data(dvd), 56 .test_dvalid(dhsyn), 57 .test_vsync(dvsyn), 58 .clk_out(dv_clk) 59 ); 60 61 defparam u1.iw = iw*dvd_chn; 62 defparam u1.ih = ih + 1; 63 defparam u1.dw = dvd_dw; 64 defparam u1.h_total = h_total; 65 defparam u1.v_total = v_total; 66 defparam u1.sync_b = sync_b; 67 defparam u1.sync_e = sync_e; 68 defparam u1.vld_b = vld_b; 69 70 71 /*local clk: also clk of all local modules*/ 72 reg cap_clk = 1'b0; 73 74 /*video capture: capture image src and transfer it into local timing*/ 75 histogram histogram_inst( 76 .RSTn(reset_l), //全局復位 77 .CLOCK(cap_clk), //系統時鐘 78 79 .IMG_CLK(pixel_clk), //像素時鐘 80 .IMG_DVD(dvd), //像素值 81 .IMG_DVSYN(dvsyn), //輸入場信號 82 .IMG_DHSYN(dhsyn), //輸入數據有效信號 83 .HIST_DAT(HIST_DAT), //輸出直方圖統計數據 84 .HIST_VALID(HIST_VALID), //輸出直方圖統計有效 85 .HIST_RDY(1'b1), //數據讀出請求 86 .HIST_INT(HIST_INT), //數據中斷輸出 87 .HIST_CLK(HIST_CLK) //數據輸出時鐘 88 ); 89 90 initial 91 begin: init 92 reset_l <= 1'b1; 93 src_sel <= 4'b0000; 94 #(100); //reset the system 95 reset_l <= 1'b0; 96 #(100); 97 reset_l <= 1'b1; 98 end 99 100 //dv_clk generate 101 always@(reset_l or pixel_clk)begin 102 if((~(reset_l)) == 1'b1) 103 pixel_clk <= 1'b0; 104 else 105 begin 106 if(clk_freq == 48) //48MHz 107 pixel_clk <= #10417 (~(pixel_clk)); 108 109 else if(clk_freq == 51.84) //51.84MHz 110 pixel_clk <= #9645 (~(pixel_clk)); 111 112 else if(clk_freq == 72) //72MHz 113 pixel_clk <= #6944 (~(pixel_clk)); 114 end 115 end 116 117 //cap_clk generate: 25MHz 118 always@(reset_l or cap_clk)begin 119 if((~(reset_l)) == 1'b1) 120 cap_clk <= 1'b0; 121 else 122 cap_clk <= #20000 (~(cap_clk)); 123 end 124 125 wire clk; 126 assign clk = ~cap_clk; 127 128 generate 129 if(cap_en != 0) begin :capture_operation 130 integer fid, cnt_cap=0; 131 132 always@(posedge clk or negedge reset_l)begin 133 if(((~(reset_l))) == 1'b1) 134 cnt_cap = 0; 135 else 136 begin 137 if(HIST_VALID == 1'b1 && HIST_CLK == 1'b0) 138 begin 139 fid = $fopen("E:/Modelsim/histogram_2d/sim/hist_result.txt","r+"); 140 $fseek(fid,cnt_cap,0); 141 $fdisplay(fid,"%8x",HIST_DAT); 142 $fclose(fid); 143 cnt_cap<=cnt_cap+10; 144 end 145 end 146 end 147 end 148 endgenerate 149 150 endmodule 151
用於modelsim仿真的.do文件以下:
1 #切換至工程目錄 2 cd E:/Modelsim/histogram_2d/sim 3 4 #打開工程 5 project open E:/Modelsim/histogram_2d/sim/histogram_2d 6 7 #添加指定設計文件 8 project addfile E:/Modelsim/histogram_2d/sim/histogram_tb.v 9 project addfile E:/Modelsim/histogram_2d/src/cross_clock_fifo.v 10 project addfile E:/Modelsim/histogram_2d/src/hist_buffer.v 11 project addfile E:/Modelsim/histogram_2d/src/histogram.v 12 project addfile E:/Modelsim/histogram_2d/src/histogram_2d.v 13 project addfile E:/Modelsim/histogram_2d/src/image_src.v 14 project addfile E:/Modelsim/histogram_2d/src/line_buffer_new.v 15 project addfile E:/Modelsim/histogram_2d/src/rgb2gray.v 16 project addfile E:/Modelsim/histogram_2d/src/RGB2YCbCr.v 17 project addfile E:/Modelsim/histogram_2d/src/video_cap.v 18 19 #編譯工程內的全部文件 20 project compileall 21 22 #仿真work庫下面的histogram_tb實例,同時調用altera_lib庫,不進行任何優化 23 vsim -t 1ps -novopt -L altera_lib work.histogram_tb 24 25 #添加輸入灰度圖像信號 26 add wave -divider GRAYImg 27 28 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/clk 29 30 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/vsync 31 32 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/din_valid 33 34 add wave -radix hex -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/din 35 36 #輸入信號緩存 37 add wave -divider Data_Cache 38 39 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/vsync_r 40 41 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/dvalid_r 42 43 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/dvalid_r2 44 45 add wave -radix hex -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/din_r 46 47 add wave -radix hex -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/din_r2 48 49 #統計開始、結束;統計使能 50 add wave -divider Statistics_Signal 51 52 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/hsync_rise 53 54 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/hsync_fall 55 56 add wave -radix unsigned -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/hsync_count 57 58 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/hsync_fall 59 60 #添加雙口RAM讀寫控制時序 61 add wave -divider HIST_BUFFER_WR 62 63 add wave -radix unsigned -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/rst_cnt 64 65 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/inc_en 66 67 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/we_a 68 69 add wave -radix unsigned -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/count_value 70 71 add wave -radix unsigned -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/addr_a 72 73 #Buff數據讀出控制時序 74 add wave -divider HIST_BUFFER_RD 75 76 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/rstOutput 77 78 add wave -radix unsigned -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/out_pixel 79 80 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/count_all 81 82 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/clr_flag 83 84 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/int_flag 85 86 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/int_r 87 88 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/we_b_l 89 90 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/we_b_h 91 92 add wave -radix unsigned -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/mux_addr_b 93 94 add wave -radix unsigned -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/mux_addr_b2 95 96 #添加統計輸出信號 97 add wave -divider Statistics_Out 98 99 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/dout_valid 100 101 add wave -radix binary -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/dout_clk 102 103 add wave -radix unsigned -position insertpoint sim:/histogram_tb/histogram_inst/histogram_2d_inst/dout 104 105 #復位 106 restart 107 108 #取消警告 109 set StdArithNoWarnings 1 110 111 #開始 112 run 16.1ms
用於數據處理的Maltab文件以下:
1 clc; 2 clear; 3 4 fid1 = fopen('hist_result.txt','r'); %FPGA轉換灰度圖像 5 data1 = fscanf(fid1,'%8x'); 6 fclose(fid1); 7 8 RGBImg = imread('lena_512x512.jpg'); %rgb原始圖像 9 RGBImg = imresize(RGBImg,[512 640]); 10 11 GRAYImg = rgb2gray(RGBImg); %Matlab變換灰度圖像 12 13 fid2 = fopen('gray_image.txt','r'); %FPGA轉換灰度圖像 14 data2 = fscanf(fid2,'%2x'); 15 data2 = uint8(data2); 16 gray_data = reshape(data2,640,512); 17 gray_data = gray_data'; 18 fclose(fid2); 19 20 figure(1); 21 subplot(2,2,1); 22 imshow(GRAYImg); 23 title('Matlab變換灰度圖像'); 24 subplot(2,2,2); 25 imhist(GRAYImg); 26 title('Matlab統計直方圖'); 27 subplot(2,2,3); 28 imshow(gray_data); 29 title('FPGA變換灰度圖像'); 30 subplot(2,2,4); 31 bar(data1); 32 title('FPGA統計直方圖');
(1)輸入信號緩存時序:
(2)統計數據寫入控制時序:
(3)統計數據讀出控制時序:
(4)FPGA直方圖統計結果與Maltab直方圖統計結果對比: