基於Modelsim的直方圖統計算法仿真

1、前言

    本篇主要針對牟新剛編著《基於FPGA的數字圖像處理及應用》第六章第五節中直方圖統計相關類容進行總結,包括代碼實現及算法

基於Modelsim的仿真。書讀百遍,其意自現。 2020-03-09 22:16:07緩存

2、基於FPGA的直方圖算法統計原理

  設計難點:異步

    (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個時鐘,奇數時鐘輸出,偶數時鐘清零

3、代碼實現

  代碼的部分參照書中的代碼實現,並與前面灰度圖像生成代碼進行整合編譯仿真。惟一須要特別注意的是在實例化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統計直方圖');

 

4、仿真結果

(1)輸入信號緩存時序:

 
 (2)統計數據寫入控制時序:

(3)統計數據讀出控制時序:

(4)FPGA直方圖統計結果與Maltab直方圖統計結果對比:

 

相關文章
相關標籤/搜索