基于Modelsim的直方图均衡化算法仿真

一、前言

  本篇主要针对牟新刚编著《基于FPGA的数字图像处理原理及应用》中关于直方图

均衡化算法的功能仿真验证。2020-03-15 10:43:27

二、FPGA直方图均衡化算法原理

  直方图均衡化又称为灰度均衡化,是指通过某种灰度映射使输入图像转换为在每一

灰度级上都有近似相同的输出图像(即输出的直方图是均匀的)。在经过均衡化处理后

的图像中,像素将占有尽可能多的灰度级并且分布均匀。因此,这样的图像将具有较高

的对比度和较大的动态范围,直方图均衡可以很好地解决相机过曝光或曝光不足的问题。

  直方图均衡化计算步骤如下:

  (1)首先计算出当前图像的直方图;

  (2)其次计算像素直方图累计和;

       (3)将上式乘以灰度值的最大值;

       (4)将上式除以图像像素总数,我们也将后两步运算统称为归一化运算。

   1.直方图累计和

    直方图累加和的定义是小于指定像素的所有像素的统计值之和。

   2.归一化计算

    归一化计算的步骤是先乘以灰度最大值,然后再除以像素总数:

             图像宽度x图像高度。

三、代码实现

  代码包括直方图归一化计算文件hist_equalized、直方图累加和统计文件histogram_2d文件

及顶层文件hist_equal。

  (1)histogram_2d.v文件中加入了累加和统计模块,主要加入了一个用于累加和统计的帧

双端口RAM;

  1 `timescale 1ps/1ps
  2 
  3 `define Equalize 1
  4 //==============================================================================//
  5 //FileName: histogram_2d.v
  6 //Date: 2020-02-29
  7 //==============================================================================//
  8 
  9 module histogram_2d(
 10     rst_n,
 11     clk,
 12     din_valid,            //输入有效
 13     din,                //输入待统计的数据
 14     dout,                //统计输出
 15     vsync,                //输入场同步
 16     dout_valid,            //输出有效
 17     rdyOutput,            //数据读出请求
 18     //dout_clk            //数据输出时钟    
 19     `ifdef Equalize
 20         hist_cnt_addr,
 21         hist_cnt_out,
 22     `endif
 23     int_flag            //中断输出
 24     
 25 );
 26 
 27     //模块入口参数
 28     parameter DW = 14;        //数据位宽
 29     parameter IH = 512;        //图像高度
 30     parameter IW = 640;        //图像宽度
 31     parameter TW = 32;        //直方图统计数据位宽
 32     
 33     localparam TOTAL_CNT = IW * IH;        //像素总数
 34     localparam HALF_WIDTH = (TW >> 1);    //将32位的数据位宽拆分为高低16位
 35     
 36     
 37     //输入输出声明
 38     input rst_n;
 39     input clk;
 40     input din_valid;
 41     input [DW-1:0] din;
 42     input rdyOutput;
 43     
 44     output reg [HALF_WIDTH:0] dout;
 45     
 46     //output wire [TW-1:0] dout;
 47     
 48     input vsync;
 49     output reg dout_valid;
 50     output reg int_flag;
 51     //output dout_clk;
 52     
 53     `ifdef Equalize
 54         input [DW-1:0] hist_cnt_addr;
 55         output reg [TW-1:0] hist_cnt_out;
 56     `endif
 57     
 58     //变量声明
 59     reg vsync_r;
 60     reg dvalid_r;
 61     reg dvalid_r2;
 62     reg [DW-1:0] din_r;
 63     reg [DW-1:0] din_r2;
 64     
 65     wire hsync_fall;
 66     wire hsync_rise;
 67     
 68     reg [9:0] hsync_count;
 69     reg count_en;
 70     wire [DW-1:0] mux_addr_b;
 71     wire [DW-1:0] mux_addr_b2;
 72     
 73     wire [TW-1:0] q_a;
 74     wire [TW-1:0] q_b;
 75     reg [TW-1:0] counter;
 76     
 77     wire [TW-1:0] count_value;
 78     wire rst_cnt;            //统计计数器复位信号
 79     wire inc_en;            //递增使能信号
 80     
 81     //DPRAM 信号
 82     wire we_a;
 83     wire we_b;
 84     wire we_b_l;
 85     reg  we_b_h;
 86     
 87     wire [DW-1:0] addr_a;
 88     //中断寄存器
 89     reg int_r;
 90     wire [DW-1:0] clr_addr;            //清零地址
 91     reg [DW-1:0] clr_addr_r;
 92     reg [DW:0] out_pixel;            //输出计数
 93     
 94     reg count_all;                    //统计完成信号
 95     //reg count_en_r;
 96     reg count_en_r;
 97     
 98     reg [TW-1:0] hist_cnt;            //直方图统计累加寄存器
 99     wire rstOutput;                    //读出电路复位信号
100     
101     wire [TW-1:0] dataTmp2;
102     wire clr_flag;                    //全局清零
103     
104     //将输入数据打两拍
105     always@(posedge clk or negedge rst_n)begin
106         if(((~(rst_n))) == 1'b1)
107         begin
108             vsync_r     <= #1 1'b0;
109             dvalid_r     <= #1 1'b0;
110             dvalid_r2     <= #1 1'b0;
111             din_r        <= #1 {DW{1'b0}};
112             din_r2        <= #1 {DW{1'b0}};
113         end
114         else
115         begin
116             vsync_r        <= #1 vsync;
117             dvalid_r    <= #1 din_valid;
118             dvalid_r2    <= #1 dvalid_r;
119             din_r        <= #1 din;
120             din_r2        <= #1 din_r;
121         end    
122     end
123     
124     //输入行同步计数,确定统计的开始和结束时刻
125     assign #1 hsync_fall = dvalid_r & (~(din_valid));
126     assign #1 hsync_rise = (~(dvalid_r)) & din_valid;
127     
128     always@(posedge clk or negedge rst_n)begin
129         if(((~(rst_n))) == 1'b1)
130             hsync_count <= #1 {10{1'b0}};
131         else
132         begin
133             if(vsync_r == 1'b1)
134                 hsync_count <= #1 {10{1'b0}};
135             else if(hsync_fall == 1'b1)
136                 hsync_count <= hsync_count + 10'b1;
137             else
138                 hsync_count <= hsync_count; 
139         end
140     end
141     
142     //一帧图像结束后停止统计 下一帧图像到来时开始计数
143     always@(posedge clk or negedge rst_n)begin
144         if(((~(rst_n))) == 1'b1)
145             count_en <= #1 1'b0;
146         else 
147         begin
148             if(hsync_count >= IH)
149                 count_en <= #1 1'b0;
150             else if(hsync_rise == 1'b1)
151                 count_en <= #1 1'b1;
152             else
153                 count_en <= #1 count_en;
154         end
155     end
156     
157     assign mux_addr_b     = ((count_en == 1'b1)) ? din_r : clr_addr;
158     assign mux_addr_b2     = ((count_en == 1'b1)) ? din_r : clr_addr_r;
159     
160     //统计递增计数器
161     always@(posedge clk)begin
162         if(rst_cnt == 1'b1)
163             counter <= #1 {{TW-1{1'b0}},1'b1}; //复位值为1
164         else if(inc_en == 1'b1)
165             counter <= #1 counter + {{TW-1{1'b0}},1'b1};
166         else
167             counter <= #1 counter;
168     end
169     
170     assign #1 rst_cnt = ((din_r != din_r2) | ((dvalid_r2 == 1'b1) & (dvalid_r == 1'b0))) ? 1'b1 : 1'b0;
171     assign #1 inc_en = (((din_r == din_r2) & (dvalid_r2 == 1'b1))) ? 1'b1 : 1'b0;
172     assign #1 we_a = ((((din_r != din_r2) & (dvalid_r2 == 1'b1)) |((dvalid_r2 == 1'b1) & (dvalid_r == 1'b0)))) ? 1'b1 : 1'b0;
173     assign #1 count_value = ((count_en == 1'b1)) ? counter+q_b : {TW{1'b0}};
174     assign #1 addr_a = din_r2;
175     
176     
177     //直方图存储器 分高16位和低16位分别存储
178     hist_buffer dpram_bin_l(
179         .address_a(addr_a),                        //输入地址为像素灰度值
180         .address_b(mux_addr_b),                    //读出和清零地址
181         .clock(clk),                            //同步时钟
182         .data_a(count_value[HALF_WIDTH-1:0]),    //当前计数值
183         .data_b({HALF_WIDTH{1'b0}}),            //清零数据
184         .wren_a(we_a),
185         .wren_b(we_b_l),
186         .q_a(q_a[HALF_WIDTH-1:0]),
187         .q_b(q_b[HALF_WIDTH-1:0])    
188     );
189     
190 
191     hist_buffer dpram_bin_h(
192         .address_a(addr_a),
193         .address_b(mux_addr_b2),
194         .clock(clk),
195         .data_a(count_value[TW-1:HALF_WIDTH]),
196         .data_b({HALF_WIDTH{1'b0}}),
197         .wren_a(we_a),
198         .wren_b(we_b_h),
199         .q_a(q_a[TW-1:HALF_WIDTH]),
200         .q_b(q_b[TW-1:HALF_WIDTH])
201     );
202     
203     always@(posedge clk or negedge rst_n)begin
204         if(((~(rst_n))) == 1'b1)
205             count_en_r <= #1 1'b0;
206         else 
207             count_en_r <= #1 count_en;
208     end
209     
210     //读出电路逻辑,计数时不能输出,读出请求时才输出
211     assign rstOutput = count_en_r | (~(rdyOutput));
212     
213     //输出像素计数
214     always@(posedge clk)begin
215         if(rstOutput == 1'b1)
216             out_pixel <= {DW+1{1'b0}};
217         else begin
218             if((~count_all) == 1'b1)
219             begin
220                 if(out_pixel == (((2 ** (DW + 1)) - 1)))
221                     out_pixel <= #1 {DW+1{1'b0}}; //输出完毕
222                 else
223                     out_pixel <= #1 out_pixel + 1'b1;
224             end
225         end
226     end
227     
228     //统计结束信号
229     always@(posedge clk)begin
230         //count_all_r <= (~rstOutput);
231         we_b_h <= we_b_l;
232         clr_addr_r <= clr_addr;
233         if(out_pixel == (((2 ** (DW + 1)) - 1)))
234             count_all <= #1 1'b1;
235         else if(count_en == 1'b1)
236             count_all <= #1 1'b0;
237     end
238     
239     //全局清零信号
240     assign clr_flag = vsync;
241     
242     //中断输出 信号读出操作完成
243     always@(posedge clk or negedge rst_n)begin
244         if((~(rst_n)) == 1'b1)
245         begin
246             int_flag     <= 1'b1;
247             int_r         <= 1'b1;
248         end
249         else
250         begin
251             int_flag <= #1 int_r;
252             if(clr_flag == 1'b1)
253                 int_r <= #1 1'b1;
254             else if(out_pixel >= (((2 ** (DW + 1)) - 1)))
255                 int_r <= #1 1'b0;
256         end
257     end
258     
259     assign we_b_l = (((out_pixel[0] == 1'b1) & (count_all == 1'b0))) ? 1'b1 : 1'b0;
260     
261     //清零地址,与读出地址反相
262     assign clr_addr = out_pixel[DW:1];
263     
264     wire dout_valid_temp;
265     
266     wire [HALF_WIDTH-1:0] dout_temp;
267     
268     always@(posedge clk or negedge rst_n)begin
269         if((~(rst_n)) == 1'b1)
270         begin
271             dout <= {HALF_WIDTH{1'b0}};
272             dout_valid <= 1'b0;
273         end
274         else
275         begin
276             dout <= #1 dout_temp;
277             dout_valid <= #1 dout_valid_temp;
278         end
279     end
280     
281     assign dout_temp = (we_b_l == 1'b1) ? q_b[HALF_WIDTH-1:0] : q_b[TW-1:HALF_WIDTH];
282     
283     assign dout_valid_temp = we_b_h | we_b_l; //输出使能
284     
285     //assign dout_clk = (dout_valid) ? we_b_h : 1'b0;
286     
287     //assign dout = q_b;
288     
289     always@(posedge clk or negedge rst_n)begin
290         if((~(rst_n)) == 1'b1)
291             hist_cnt <= {TW{1'b0}};                    //复位清零
292         else begin
293             if(vsync_r == 1'b0 & vsync == 1'b1)     //新的一帧到来时清零
294                 hist_cnt <= {TW{1'b0}};
295             else if(out_pixel[0] == 1'b1)            //每个像素读出时刻
296                 hist_cnt <= hist_cnt + q_b;            //将结果累加
297             else
298                 hist_cnt <= hist_cnt;
299         end
300     end
301     
302     reg [DW:0] out_pixel_r;
303     reg [DW-1:0] out_pixel_r2;
304     
305     wire [TW-1:0] hist_cnt_temp;
306     
307     always@(posedge clk or negedge rst_n)begin
308         if((~(rst_n)) == 1'b1)begin
309             out_pixel_r     <= {DW+1{1'b0}};
310             out_pixel_r2     <= {DW{1'b0}};
311             hist_cnt_out    <= {TW{1'b0}};
312         end
313         else begin
314             out_pixel_r     <= #1 out_pixel;
315             out_pixel_r2     <= #1 out_pixel_r[DW:1];
316             hist_cnt_out    <= #1 hist_cnt_temp;    //将数据打一拍后输出
317         end
318     end
319     
320     hist_buffer_cnt hist_cnt_buf(
321         .address_a(out_pixel_r2),        //写入地址,直方图当前地址
322         .address_b(hist_cnt_addr),        //读出地址
323         .clock(clk),                    //同步时钟
324         .data_a(hist_cnt),                //写入数据
325         .data_b(),                        
326         .wren_a(dout_valid),            //写入时刻:直方图数据有效
327         .wren_b(1'b0),                    
328         .q_a(),
329         .q_b(hist_cnt_temp)                //输出数据    
330     );
331     
332 endmodule

  (2) hist_equalized.v文件主要用于计算直方图均衡化后的像素值,其中计算开销6个时钟,咋来的?

  1 `timescale 1ps/1ps 
  2 
  3 //==========================================================================================================//
  4 //FileName: hist_equalized.v
  5 //Date: 2020-03-12
  6 //==========================================================================================================//
  7 
  8 module hist_equalized(
  9     rst_n,
 10     clk,
 11     din_valid,        //输入数据有效
 12     din,            //输入数据
 13     dout,            //输出数据
 14     vsync,            //输入场同步
 15     dout_valid,        //输出有效
 16     vsync_out        //输出场同步
 17 );
 18 
 19     parameter DW = 8;    //数据位宽
 20     parameter IH = 512;    //图像高度
 21     parameter IW = 640;    //图像宽度
 22     parameter TW = 32;    //直方图数据位宽
 23     
 24     localparam TOTAL_CNT = IW * IH;
 25     localparam HALF_WIDTH = (TW >> 1);
 26     
 27     //计算开销
 28     localparam latency = 6;
 29     
 30     input rst_n;
 31     input clk;
 32     input din_valid;
 33     input [DW-1:0] din;
 34     output [DW-1:0] dout;
 35     input vsync;
 36     output vsync_out;
 37     output dout_valid;
 38     
 39     reg [DW-1:0] hist_cnt_addr;
 40     wire [TW-1:0] hist_cnt_out;
 41     
 42     //首先需例化一个直方图统计模块对输入图像进行直方图统计
 43     //注意我们只需要得到直方图统计累加和信息
 44     
 45     histogram_2d hist(
 46         .rst_n(rst_n),
 47         .clk(clk),
 48         .din_valid(din_valid),
 49         .din(din),
 50         .vsync(vsync),
 51         .dout(),                        //直方图统计输出
 52         .dout_valid(),                    //输出有效
 53         .rdyOutput(),                    //数据读出请求
 54         .hist_cnt_addr(hist_cnt_addr),     //累加和输入地址
 55         .hist_cnt_out(hist_cnt_out),    //累加和输出
 56         .int_flag()
 57     );
 58     
 59     defparam hist.DW = DW;
 60     defparam hist.IH = IH;
 61     defparam hist.IW = IW;
 62     
 63     wire vsync_fall;
 64     wire valid;
 65     reg [1:0] frame_cnt;
 66     reg hist_valid_temp;
 67     reg vsync_r;
 68     
 69     //由于至少需要等到第一帧输出完毕之后才能完成第一帧数据的直方图统计信息,
 70     //因此有必要对图像帧进行计数
 71     always@(posedge clk or negedge rst_n)begin
 72         if((~(rst_n)) == 1'b1)begin
 73             vsync_r <= #1 1'b0;
 74             hist_valid_temp <= 1'b0;
 75             frame_cnt <= 2'b0;
 76         end
 77         else begin
 78             vsync_r <= #1 vsync;
 79             
 80             if(vsync_fall)
 81                 frame_cnt <= frame_cnt + 2'b01;    //每帧结束时帧计数加1
 82             else
 83                 frame_cnt <= frame_cnt;
 84                 
 85             if(frame_cnt >= 2'b10)    //第二帧开始输入均衡操作才开始有效
 86                 hist_valid_temp <= 1'b1;
 87         end
 88     end
 89     
 90     //场同步下降沿信号
 91     assign vsync_fall = (vsync & ~vsync_r);
 92     
 93     //全局有效信号
 94     assign valid = hist_valid_temp & din_valid;
 95     
 96     //缓存全局有效信号,完成时序对齐
 97     reg [latency:0] valid_r;
 98     
 99     always@(posedge clk or negedge rst_n)begin
100         if((~(rst_n)) == 1'b1)begin
101             valid_r[latency:0] <= {latency+1{1'b0}};
102         end
103         else begin
104             valid_r <= #1 {valid_r[latency-1:0],valid};
105         end
106     end
107     
108     reg [DW-1:0] din_r;
109     
110     //缓存输入数据完成时序对齐
111     always@(posedge clk or negedge rst_n)begin
112         if((~(rst_n)) == 1'b1)begin
113             din_r <= {DW{1'b0}};
114         end
115         else begin
116             din_r <= #1 din;
117         end
118     end
119     
120     //查询当前像素的直方图统计累加和
121     always@(posedge clk or negedge rst_n)begin
122         if((~(rst_n)) == 1'b1)begin
123             hist_cnt_addr <= {DW{1'b0}};
124         end
125         else begin
126             if(valid_r[0])
127                 hist_cnt_addr <= #1 din_r;
128             else
129                 hist_cnt_addr <= hist_cnt_addr;
130         end
131     end
132     
133     reg [2*TW-1:0] mul_temp[0:2];
134     reg [DW-1:0] dout_temp;
135     
136     //对于分辨率512*512的图像而言
137     generate
138         if((IW == 512) & (IH == 512))begin : IW_512
139             always@(posedge clk or negedge rst_n)
140                 if((~(rst_n)) == 1'b1)begin
141                     mul_temp[0] <= {2*TW{1'b0}};
142                 end
143                 else begin
144                     if(valid_r[1])
145                         //hist_cnt_out*255 - 1,
146                         mul_temp[0] <= {{TW-DW{1'b0}},hist_cnt_out[TW-1:0],{DW{1'b0}}} - {{TW{1'b0}},hist_cnt_out};
147                     if(valid_r[1])
148                         //hist_cnt_out/(512*512) IW = IH =512
149                         mul_temp[1] <= #1 {{18{1'b0}},mul_temp[0][2*TW-1:18]};
150                     if(valid_r[2])
151                         dout_temp <= #1 mul_temp[1][DW-1:0];    
152                 end
153         end
154     endgenerate
155     
156     //对于分辨率为640*512的图像而言
157     generate
158         if(IW == 640 & IH == 512)begin : IW_640
159             wire [2*TW-1:0] dout_temp_r/*synthesis keep*/;
160             
161             assign dout_temp_r = {{16{1'b0}},mul_temp[2][2*TW-1:16]};
162             
163             always@(posedge clk or negedge rst_n)
164                 if((~(rst_n)) == 1'b1)begin
165                     mul_temp[0] <= {2*TW{1'b0}};
166                 end
167                 else begin
168                     if(valid_r[1])
169                     //hist_cnt_out*51,DW must be 8
170                     //hist_cnt_out*32 + hist_cnt_out*16
171                     mul_temp[0] <= #1 {{TW-5{1'b0}},hist_cnt_out[TW-1:0],{5{1'b0}}} + {{TW-4{1'b0}},hist_cnt_out[TW-1:0],{4{1'b0}}};
172                     //hist_cnt_out*1 + hist_cnt_out*2
173                     mul_temp[1] <= #1 {{TW{1'b0}},hist_cnt_out[TW-1:0]} + {{TW-1{1'b0}},hist_cnt_out[TW-1:0],{1{1'b0}}};
174                     
175                     if(valid_r[1])
176                         //hist_cnt_out/(64*2*512)
177                         mul_temp[2] <= #1 mul_temp[0] + mul_temp[1];
178             
179                     if(valid_r[2])
180                         dout_temp <= #1 dout_temp_r[DW-1:0];
181                 end
182         end
183     endgenerate
184     
185     //完成数据输出对齐
186     assign dout = dout_temp;
187     assign dout_valid = valid_r[latency];
188     assign vsync_out = vsync;
189     
190 endmodule

  (6)用于功能仿真的顶层文件,包含图像数据的捕获、灰度图像转换及图像均衡化模块;

  1 `timescale 1ps/1ps
  2 
  3 //=========================================================================================//
  4 //FileName: hist_equal.v TOP FILE
  5 //Date: 2020-03-12
  6 //=========================================================================================//
  7 
  8 module hist_equal(
  9     RSTn,                //全局复位
 10     CLOCK,                //系统时钟
 11     
 12     IMG_CLK,            //像素时钟
 13     IMG_DVD,            //像素值
 14     IMG_DVSYN,            //输入场信号
 15     IMG_DHSYN,            //输入数据有效信号
 16     HISTEQUAL_DAT,        //输出直方均衡化数据
 17     HISTEQUAL_VALID,    //输出直方均衡化有效信号
 18     HISTEQUAL_VSYNC        //输出直方图均衡化场有效信号
 19 );
 20 
 21     /*image parameter*/
 22     parameter iw             = 640;        //image width
 23     parameter ih            = 512;        //image height
 24     parameter trig_value    = 400;         //250
 25     parameter tw            = 32;        //直方图统计数据位宽
 26     
 27     localparam half_width    = (tw >> 1); //将32位的数据位宽拆分为高低16位
 28     
 29     /*data width*/
 30     parameter dvd_dw     = 8;    //image source data width
 31     parameter dvd_chn    = 3;    //channel of the dvd data: when 3 it's rgb or 4:4:YCbCr
 32     parameter local_dw    = dvd_dw * dvd_chn;    //local algorithem process data width
 33     parameter cmd_dw    = dvd_dw * dvd_chn;    //local algorithem process data width
 34 
 35     //Port Declared
 36     input RSTn;
 37     input CLOCK;
 38     input IMG_CLK;
 39     input [dvd_dw-1:0] IMG_DVD;
 40     input IMG_DVSYN;
 41     input IMG_DHSYN;
 42     output [dvd_dw-1:0] HISTEQUAL_DAT;
 43     output HISTEQUAL_VALID;
 44     output HISTEQUAL_VSYNC;
 45 
 46     
 47     //Variable Declared
 48     wire GRAY_CLK;
 49     wire GRAY_VSYNC;
 50     wire GRAY_DVALID;
 51     wire [dvd_dw-1:0] Y_DAT;
 52     wire [dvd_dw-1:0] Cb_DAT;
 53     wire [dvd_dw-1:0] Cr_DAT;
 54     
 55     wire [local_dw-1:0] RGB_DAT;
 56     wire RGB_DVALID;
 57     wire RGB_VSYNC;
 58     
 59     video_cap video_cap_inst(
 60             .reset_l(RSTn),                //异步复位信号
 61             .DVD(IMG_DVD),                //输入视频流
 62             .DVSYN(IMG_DVSYN),            //输入场同步信号
 63             .DHSYN(IMG_DHSYN),            //输入行同步
 64             .DVCLK(IMG_CLK),            //输入DV时钟
 65             .cap_dat(RGB_DAT),            //输出RGB通道像素流,24位
 66             .cap_dvalid(RGB_DVALID),    //输出数据有效
 67             .cap_vsync(RGB_VSYNC),        //输出场同步
 68             .cap_clk(CLOCK),            //本地逻辑时钟
 69             .img_en(),                
 70             .cmd_rdy(),                    //命令行准备好,代表可以读取
 71             .cmd_rdat(),                //命令行数据输出
 72             .cmd_rdreq()                //命令行读取请求
 73         );
 74     
 75     defparam video_cap_inst.DW_DVD         = dvd_dw;
 76     defparam video_cap_inst.DW_LOCAL     = local_dw;
 77     defparam video_cap_inst.DW_CMD         = cmd_dw;
 78     defparam video_cap_inst.DVD_CHN     = dvd_chn;
 79     defparam video_cap_inst.TRIG_VALUE  = trig_value;
 80     defparam video_cap_inst.IW             = iw;
 81     defparam video_cap_inst.IH             = ih;
 82     
 83     RGB2YCrCb RGB2YCrCb_Inst(
 84             .RESET(RSTn),                //异步复位信号
 85             
 86             .RGB_CLK(CLOCK),            //输入像素时钟
 87             .RGB_VSYNC(RGB_VSYNC),        //输入场同步信号
 88             .RGB_DVALID(RGB_DVALID),    //输入数据有信号
 89             .RGB_DAT(RGB_DAT),            //输入RGB通道像素流,24位
 90             
 91             .YCbCr_CLK(GRAY_CLK),        //输出像素时钟
 92             .YCbCr_VSYNC(GRAY_VSYNC),    //输出场同步信号
 93             .YCbCr_DVALID(GRAY_DVALID),    //输出数据有效信号
 94             .Y_DAT(Y_DAT),                //输出Y分量
 95             .Cb_DAT(Cb_DAT),            //输出Cb分量
 96             .Cr_DAT(Cr_DAT)                //输出Cr分量
 97         );    
 98 
 99     defparam RGB2YCrCb_Inst.RGB_DW = local_dw;
100     defparam RGB2YCrCb_Inst.YCbCr_DW = dvd_dw;
101 
102 
103     hist_equalized hist_equalized_inst(
104         .rst_n(RSTn),
105         .clk(GRAY_CLK),
106         .din_valid(GRAY_DVALID),        //输入数据有效
107         .din(Y_DAT),                    //输入数据
108         .dout(HISTEQUAL_DAT),            //输出数据
109         .vsync(GRAY_VSYNC),                //输入场同步
110         .dout_valid(HISTEQUAL_VALID),    //输出有效
111         .vsync_out(HISTEQUAL_VSYNC)        //输出场同步
112     );
113     
114     defparam hist_equalized_inst.DW = dvd_dw;
115     defparam hist_equalized_inst.IH = ih;
116     defparam hist_equalized_inst.IW = iw;
117     defparam hist_equalized_inst.TW = tw;
118     
119 endmodule

  (4)用于Modelsim仿真的testbench文件;

  1 `timescale 1ps/1ps
  2 
  3 module histequalized_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     /*test module enable*/
 28     parameter hist_equalized_en    = 1;
 29 
 30     /*signal group*/
 31     reg pixel_clk = 1'b0;
 32     reg reset_l;
 33     reg [3:0] src_sel;
 34 
 35 
 36     /*input dv group*/
 37     wire dv_clk;
 38     wire dvsyn;
 39     wire dhsyn;
 40     wire [dvd_dw-1:0] dvd;
 41     
 42     /*dvd source data generated for simulation*/
 43     image_src image_src_inst//#(iw*dvd_chn, ih+1, dvd_dw, h_total, v_total, sync_b, sync_e, vld_b)
 44     (
 45         .clk(pixel_clk),
 46         .reset_l(reset_l),
 47         .src_sel(src_sel),
 48         .test_data(dvd),
 49         .test_dvalid(dhsyn),
 50         .test_vsync(dvsyn),
 51         .clk_out(dv_clk)
 52     );
 53         
 54     defparam image_src_inst.iw = iw*dvd_chn;
 55     defparam image_src_inst.ih = ih + 1;
 56     defparam image_src_inst.dw = dvd_dw;
 57     defparam image_src_inst.h_total = h_total;
 58     defparam image_src_inst.v_total = v_total;
 59     defparam image_src_inst.sync_b = sync_b;
 60     defparam image_src_inst.sync_e = sync_e;
 61     defparam image_src_inst.vld_b = vld_b;
 62     
 63     /*local clk: also clk of all local modules*/
 64     reg cap_clk = 1'b0;
 65         
 66     /*hist equalized operation module*/
 67     generate
 68         if(hist_equalized_en != 0)begin : equalized_operation
 69             wire equalized_dvalid;
 70             wire [dvd_dw-1:0] equalized_data;
 71             wire equalized_vsync;
 72             
 73             wire equalized_dvalid_in;
 74             wire [dvd_dw-1:0] equalized_data_in;
 75             wire equalized_vsync_in;
 76         
 77             integer fp_equalized,cnt_equalized = 0;
 78         
 79             /*video capture: capture image src and transfer it into local timing*/
 80             hist_equal hist_equal_inst(
 81                 .RSTn(reset_l),                        //全局复位
 82                 .CLOCK(cap_clk),                    //系统时钟
 83                 
 84                 .IMG_CLK(pixel_clk),                //像素时钟
 85                 .IMG_DVD(equalized_data_in),        //像素值
 86                 .IMG_DVSYN(equalized_vsync_in),        //输入场信号
 87                 .IMG_DHSYN(equalized_dvalid_in),    //输入数据有效信号
 88                 .HISTEQUAL_DAT(equalized_data),        //输出直方图统计数据
 89                 .HISTEQUAL_VALID(equalized_dvalid),    //输出直方图统计有效
 90                 .HISTEQUAL_VSYNC(equalized_vsync)    //数据读出请求
 91             );
 92             
 93             assign equalized_data_in = dvd;
 94             assign equalized_dvalid_in = dhsyn;
 95             assign equalized_vsync_in = dvsyn;
 96     
 97             always@(posedge cap_clk or posedge equalized_vsync)begin
 98                 if((~(equalized_vsync)) == 1'b0)
 99                     cnt_equalized = 0;
100                 else begin
101                     if(equalized_dvalid == 1'b1)begin
102                         fp_equalized = $fopen("E:/Modelsim/hist_equalized/sim/equalized.txt","r+");
103                         $fseek(fp_equalized,cnt_equalized,0);
104                         $fdisplay(fp_equalized,"%02X",equalized_data);
105                         $fclose(fp_equalized);
106                         cnt_equalized <= cnt_equalized + 4;
107                     end
108                 end
109             end
110         end
111     endgenerate
112     
113     initial
114     begin: init
115         reset_l <= 1'b1;
116         src_sel <= 4'b0000;
117         #(100);            //reset the system
118         reset_l <= 1'b0;
119         #(100);    
120         reset_l <= 1'b1;
121     end
122     
123     //dv_clk generate
124     always@(reset_l or pixel_clk)begin
125         if((~(reset_l)) == 1'b1)
126             pixel_clk <= 1'b0;
127         else 
128         begin
129             if(clk_freq == 48)            //48MHz
130                 pixel_clk <= #10417 (~(pixel_clk));
131             
132             else if(clk_freq == 51.84)    //51.84MHz
133                 pixel_clk <= #9645 (~(pixel_clk));
134             
135             else if(clk_freq == 72)        //72MHz
136                 pixel_clk <= #6944 (~(pixel_clk));
137         end
138     end
139     
140     //cap_clk generate: 25MHz
141     always@(reset_l or cap_clk)begin
142         if((~(reset_l)) == 1'b1)
143             cap_clk <= 1'b0;
144         else
145             cap_clk <= #20000 (~(cap_clk));    
146     end
147     
148     wire clk;
149     assign clk = ~cap_clk;
150     
151 endmodule
152     

  (5)用于Modelsim仿真的.do文件;

 1 #切换至工程目录
 2 cd E:/Modelsim/hist_equalized/sim
 3 
 4 #打开工程
 5 project open E:/Modelsim/hist_equalized/sim/hist_equalized
 6 
 7 #添加指定设计文件
 8 project addfile E:/Modelsim/hist_equalized/sim/histequalized_tb.v
 9 project addfile E:/Modelsim/hist_equalized/src/cross_clock_fifo.v
10 project addfile E:/Modelsim/hist_equalized/src/hist_buffer.v
11 project addfile E:/Modelsim/hist_equalized/src/hist_equal.v
12 project addfile E:/Modelsim/hist_equalized/src/hist_equalized.v
13 project addfile E:/Modelsim/hist_equalized/src/histogram_2d.v
14 project addfile E:/Modelsim/hist_equalized/src/image_src.v
15 project addfile E:/Modelsim/hist_equalized/src/line_buffer_new.v
16 project addfile E:/Modelsim/hist_equalized/src/RGB2YCbCr.v
17 project addfile E:/Modelsim/hist_equalized/src/video_cap.v
18 project addfile E:/Modelsim/hist_equalized/prj/hist_buffer_cnt.v
19 
20 #编译工程内的所有文件
21 project compileall
22 
23 #仿真work库下面的histequalized_tb实例,同时调用altera_lib库,不进行任何优化
24 vsim -t 1ps -novopt -L altera_lib work.histequalized_tb
25 
26 #添加输入灰度图像信号
27 add wave -divider GRAYImg
28 
29 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/clk
30 
31 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/vsync
32 
33 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/din_valid
34 
35 add wave -radix unsigned -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/din
36 
37 #输入信号缓存及处理
38 add wave -divider DataCache
39 
40 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/vsync_r
41 
42 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/frame_cnt
43 
44 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/hist_valid_temp
45 
46 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/vsync_fall
47 
48 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/valid
49 
50 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/valid_r
51 
52 add wave -radix unsigned -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/din_r
53 
54 add wave -radix unsigned -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/hist_cnt_addr
55 
56 #计算归一化的值
57 add wave -divider Calculator
58 
59 add wave -radix unsigned -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/mul_temp
60 
61 #add wave -radix unsigned -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/dout_temp_r
62 
63 add wave -radix unsigned -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/dout_temp
64 
65 #添加数据输出
66 add wave -divider EqualDataOut
67 
68 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/dout_valid
69 
70 add wave -radix binary -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/vsync_out
71 
72 add wave -radix unsigned -position insertpoint sim:/histequalized_tb/equalized_operation/hist_equal_inst/hist_equalized_inst/dout
73 
74 #复位
75 restart
76 
77 #取消警告
78 set StdArithNoWarnings 1
79 
80 #开始
81 run 35ms

四、仿真结果

  (1)算法时序仿真:存在两个问题,第一,书中提供的代码仿真时,帧计数有问题,主要是图像数据采集模块生成的场信号有问题;因此实际是帧计数为3时,

开始进行直方图均衡化操作。第二个问题就是计算开销latenc= 6?计算开销为6,没整明白?

  

  (2)FPGA处理结果与Matlab处理结果对比,可见算法对图像有一定增强对比度的作用,但是效果的没有Matlab直接变换的效果好;

  

猜你喜欢

转载自www.cnblogs.com/huangwei0521/p/12496362.html