直方图均衡的原理笔者就不写了,主要记录如何用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_r0;
de_r20;
end
else begin
de_rde;
de_r2de_r;
end
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
hs_r0;
else
hs_rhs;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
vs_r0;
else
vs_rvs;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
rd_addr0;
else if(de==1'b1)
rd_addrdata_in;
else if(calculate_end==1'b1)
rd_addrpo_cnt;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
wr_addr0;
else
wr_addrrd_addr;
end
assign CNT_en=(rd_addr==wr_addr)?de_r2:0;
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
CNT1'b1;
else if(CNT_en==1'b1)
CNTCNT+1'b1;
else if(CNT_en==0)
CNT1'b1;
else
CNTCNT;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
rd_data_r0;
else
rd_data_rrd_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_cnt0;
else if((row_cnt_en==1'b1)&&(row_cntIH-1))
row_cntrow_cnt+1'b1;
else if(row_cnt==IH)
row_cnt0;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
calculate_end0;
else if(row_cnt==IH)
calculate_end1'b1;
else if(po_cnt==8'd255)
calculate_end0;
else
calculate_endcalculate_end;
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
calculate_end_r0;
else
calculate_end_r{calculate_end_r[0],calculate_end};
end
always@(posedge clk or negedge reset_n)begin
if(!reset_n)
po_cnt0;
else if(calculate_end==1'b1)
po_cntpo_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),
.wr_addr(wr_addr),
.rd_addr(rd_addr),
.wr_clk(clk),
.rd_clk(clk),
.wr_en(he_wr_en),
.rst(!reset_n),
.rd_data(rd_data)
);
endmodule
截取一部分仿真图:
后续有空再加注释。
Original: https://blog.csdn.net/qq_41527741/article/details/121567657
Author: 满城風絮
Title: FPGA实现直方图均衡(一)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/645975/
转载文章受原作者版权保护。转载请注明原作者出处!