FPGA实现直方图均衡(一)

直方图均衡的原理笔者就不写了,主要记录如何用verilog写出来。
首先需要实现直方图统计,就是统计一幅图中各灰度级的像素数量。
那么这里参考《基于FPGA的数字图像处理原理及应用》这本书,也推荐大家看一看这本书,讲解了许多图像处理在FPGA中实现的方法。
首先,很显然,需要用一个ram来缓存统计数据。
那么统计的流程主要就是计数,输出数据和清零。清零很简单,只需要在
输出数据的下一个时钟对上一次输出的数据进行清零就可以了,比较简单,直接给时序图:
在这里插入图片描述

如果按照一般思路,每次将当前像素点的灰度级作为地址,然后每次读出上一次记录的数量再写入,比较耗时,所以实现的方法是,对输入数据进行一个缓存,并且缓存的数据作为读地址。然后比较当前输入数据与缓存是否相同,相同则计数器加一,不同则将计数器与读出的数据相加作为写入数据。下图是时序图:

de代表数据有效,de1和de2是de的一级缓存和二级缓存;
data_in是当前数据,也就是像素,范围是0到255;
rd_addr和wr_addr是读地址和写地址;
cnt_en是计数使能,高有效;
wr_en是写使能,高有效;
cnt是计数器,默认值是1;
rd_data是读数据,rd_data1是rd_data1的一级缓存;
wr_data是写数据,它的值是cnt与rd_data1的和;
这里要说明的是笔者使用的ram ip核是读数据无缓存的,也就是给ram读地址后,这个周期就得到数据。
那么根据上面的时序图就可以写了。
下面是全部代码

module he_top(
	input clk,
	input reset_n,
	input [7:0]data_in,
	input vs,
	input hs,
	input de,
	output [19:0]he_calculate,
	output o_he_de,
	output [7:0]o_he_addr

   );
   localparam IH='d768;
   reg	de_r;
   reg	de_r2;
   reg	hs_r;
   reg	vs_r;
   reg	[9:0]CNT;
   wire		CNT_en;
   reg	[7:0]rd_addr;
   reg	[7:0]wr_addr;
   wire		wr_en;
   
   wire	[19:0]rd_data;
   wire	[19:0]wr_data;
   reg	[19:0]rd_data_r;
   
   
   reg	[9:0] row_cnt;
   wire		  row_cnt_en;
   reg	[1:0] hs_reg;
   
   reg	[7:0]po_cnt;
   reg	calculate_end;
   reg	[1:0]calculate_end_r;
   
   always@(posedge clk or negedge reset_n)begin
		if(!reset_n)begin
			de_r<=0;
			de_r2<=0;
		end
		else begin
			de_r<=de;
			de_r2<=de_r;
		end
	end
	
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			hs_r<=0;
		else
			hs_r<=hs;
	end
   
   always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			vs_r<=0;
		else
			vs_r<=vs;
	end
	
   always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			rd_addr<=0;
		else if(de==1'b1)
			rd_addr<=data_in;
		else if(calculate_end==1'b1)
			rd_addr<=po_cnt;
	end
		
	
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			wr_addr<=0;
		else
			wr_addr<=rd_addr;
	end
	
	assign CNT_en=(rd_addr==wr_addr)?de_r2:0;
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			CNT<=1'b1;
		else if(CNT_en==1'b1)
			CNT<=CNT+1'b1;
		else if(CNT_en==0)
			CNT<=1'b1;
		else
			CNT<=CNT;
	end
	
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			rd_data_r<=0;
		else
			rd_data_r<=rd_data;
	end
	
	assign wr_en=(rd_addr==wr_addr)?0:de_r2;
	assign wr_data=calculate_end_r[1]?0:(CNT+rd_data_r);
	
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)begin
			hs_reg[0]<=0;
			hs_reg[1]<=0;
		end
		else begin
			hs_reg[0]<=hs;
			hs_reg[1]<=hs_reg[0];
		end
	end
		
	assign	row_cnt_en=((!de_r)&&(de_r2))?1'b1:0;
		
	
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			row_cnt<=0;
		else if((row_cnt_en==1'b1)&&(row_cnt<=IH-1))
			row_cnt<=row_cnt+1'b1;
		else if(row_cnt==IH)
			row_cnt<=0;
	end
		
	
	
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			calculate_end<=0;
		else if(row_cnt==IH)
			calculate_end<=1'b1;
		else if(po_cnt==8'd255)
			calculate_end<=0;
		else
			calculate_end<=calculate_end;
	end
	
	
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			calculate_end_r<=0;
		else
			calculate_end_r<={calculate_end_r[0],calculate_end};
	end
			
		
	always@(posedge clk or negedge reset_n)begin
		if(!reset_n)
			po_cnt<=0;
		else if(calculate_end==1'b1)
			po_cnt<=po_cnt+1'b1;
	end
		
	assign he_calculate=calculate_end_r[0]?rd_data:0;
	wire he_wr_en;
	assign	he_wr_en=(wr_en)||(row_cnt_en)||(calculate_end_r[1]);
	 
	assign o_he_de=calculate_end_r[0];
	assign o_he_addr=calculate_end_r[0]?rd_addr:0;
		
	he_cal he_cal_t1 (
  .wr_data(wr_data),    // input [19:0]
  .wr_addr(wr_addr),    // input [7:0]
  .rd_addr(rd_addr),    // input [7:0]
  .wr_clk(clk),      // input
  .rd_clk(clk),      // input
  .wr_en(he_wr_en),        // input
  .rst(!reset_n),            // input
  .rd_data(rd_data)     // output [19:0]
);
	
endmodule

截取一部分仿真图:
在这里插入图片描述
后续有空再加注释。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值