FPGA图像处理仿真实验——直方图均衡化

直方图均衡化实验,主要包括三部分,直方图统计、计算累加直方图、均衡化。

1、直方图统计

       直方图统计就是记录每个灰度值在图片中出现的像素次数,灰度图片有0-255个灰度级,如果我们定义256个寄存器来存储数据比较麻烦,所以借用RAM来实现直方图统计。当输入一个像素点的灰度值,将其作为地址,在RAM中读出该地址对应的数据,进行加1操作,然后再写会该地址。

       我配置了一个双端口RAM u1来进行直方图统计,当输入图片数据流有效时,读地址为输入图片数据流的灰度值,将读出的数据加一后再写回,从a端口进行读数据,从b端口进行写 数据,为了防止读写数据产生冲突,我将写数据的地址延迟了一个时钟周期;两张图片输入之间,场同步信号会有一段时间保持在低电平,这段时间没有输入图片像素数据,在这段时间将RAM中的数据读出,并将RAM清零。地址从0遍历到255,每读出一个地址的数据后,相应将该地址清零,这个过程和读出数据加一再写回的过程类似。

2、计算累加直方图

       将上一步读出的RAM数据进行累加,存放在另一个RAM u2中,u2中存放累加直方图的信息,这个过程也是在场同步信号会有一段时间保持在低电平时期完成。地址从0遍历到255,将累加后的数据sum写入RAM,地址遍历完累加直方图计算完成。

3、均衡化

       在第二张图片输入时,根据像素点灰度值对应的地址,在u2中读出累计直方图数据,通过图中的公式,计算出均衡化后的灰度值,最后将计算后的数据输出。

4、代码

 module histogram_equ(
    input clk,
    input rst_n,
    
    input per_frame_vsync,
    input per_frame_href,
    input per_frame_clken,
    input [7:0] per_img_Y,
    
    output post_frame_vsync,
    output post_frame_href,
    output post_frame_clken,
    output [7:0] post_img_Y
    );
    
localparam IMG_TOTAL_PIXEL=307200;   //640*480
localparam IMG_MAX_GRAY=256;      //0-255

//reg web;
wire [18:0] cnt,cntplus;   //同一灰度级像素个数计数器
wire [18:0] ram_his_rd_data;  //从累计直方图中读出的数据
reg vsync_delay;
wire vsync_negedge;    //场同步信号下降沿
wire vsync_posedge;    //场同步信号上升沿
reg web2;   //双端口RAM u2的写使能信号
reg tag;    //标志位
reg [7:0] dizhi;
reg [7:0] dizhi1,dizhi2;   //双端口RAM u2的写数据地址
wire [7:0] addra;    //双端口RAM  u1的a端口地址
wire [18:0] dout;    //双端口RAM  u1的输出数据
wire [18:0] din;    //双端口RAM u1的输入数据
reg [7:0] addrb;   //双端口RAM  u1的b端口地址
wire web;   //双端口RAM的写使能 
reg [18:0] sum;  //为了计算累加直方图,用于存放直方图数据的和
wire [18:0] ram_accu_rddata;   //从累加直方图中读出的数据


//统计像素个数时的写使能信号
//always @(posedge clk)
//begin
//    web<=per_frame_clken;
//    //addrb<=per_img_Y;
//end
assign cntplus=cnt+1;


//将场同步信号延时一拍
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        vsync_delay<=1'b0;
    else
        vsync_delay<=per_frame_vsync;
end
assign vsync_negedge=vsync_delay&(!per_frame_vsync);
assign vsync_posedge=(!vsync_delay)&per_frame_vsync;

always @(posedge clk)
begin
    dizhi1<=dizhi;
    dizhi2<=dizhi1;
end
//在一帧图像输入完成后需要对RAM进行数据读出和数据清0,此时的读写数据地址为变量dizhi
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        dizhi<=8'd0;
    else
        begin
            if(tag==0)
                 begin
                    if(dizhi==255)
                        dizhi<=dizhi;
                    else
                        dizhi<=dizhi+1;
                 end
        end
end
//在对累计直方图进行写操作时,只有在标志位tag=0时才进行,并且只遍历一次0-255地址
always @(posedge clk)
begin
   if(tag==0)
        begin
            if(dizhi2==255)
                web2<=0;
            else
                web2<=1;
        end
end

//当场有效信号为上升沿时,标志位置1,下降沿时,标志位置0。tag=1代表正在输入图像数据流,tag=0代表两帧图像输入数据流之间的间隙
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        tag<=1;
    else
        begin
            if(vsync_posedge)
                tag<=1;
            if(vsync_negedge)
                tag<=0;
        end
end

always @(posedge clk)
begin
    addrb<=addra;
end

assign addra=tag?per_img_Y:dizhi;  //当输入图像数据流时,地址为每个像素点图像灰度值对应的地址,当处于两帧图像输入数据流之间的间隙时,地址为0-255遍历过程的地址
assign cnt=tag?dout:cnt;  //当输入图像数据流时,cnt与u1 的输出数据相连,否则保持
assign ram_his_rd_data=web2?dout:ram_his_rd_data;  //当web2有效时,从累计直方图中读出的数据与双端口RAM u2的输出相连,否则保持
assign din=tag?cntplus:(19'd0);  //当tag=1时,输入为+1后的数据,当tag=0时,需要对RAN进行清0操作,所以输入为0
assign web=tag?per_frame_clken:1;  //tag=1时,使能信号为帧时钟使能信号,tag=0时,要对RAM进行清零操作,所以使能信号一直为1

//计算累加直方图要输入的数据
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            sum<=19'd0;
        end
    else
        begin
            if(web2==1)
                begin
                    sum<=sum+ram_his_rd_data;
                end
        end
end

//双端口RAM u1,用于存放直方图的数据,当输入图片数据流有效时,将每个像素点灰度值对应的地址存放的数据读出,再加1,然后再写回去
//在帧与帧之间的间隙,从地址0-255,将累计直方图数据读出,再将RAM清零
ram_ip u1(
    .clka(clk),
    .wea(1'b0),
    .addra(addra),  // input wire [7 : 0] addra
    .dina(0),    // input wire [18 : 0] dina
    .douta(dout),  // output wire [18 : 0] douta
    .clkb(clk),    // input wire clkb
    .web(web),      // input wire [0 : 0] web
    .addrb(addrb),  // input wire [7 : 0] addrb
    .dinb(din),    // input wire [18 : 0] dinb
    .doutb()  // output wire [18 : 0] doutb
);
//双端口RAM u2,用于存放累加直方图数据,将累加直方图的数据从a端口写入,b端口读出

ram_ip u2(
    .clka(clk),
    .wea(web2),
    .addra(dizhi2),  // input wire [7 : 0] addra
    .dina(sum),    // input wire [18 : 0] dina
    .douta(),  // output wire [18 : 0] douta
    .clkb(per_frame_clken),    // input wire clkb
    .web(1'b0),      // input wire [0 : 0] web
    .addrb(per_img_Y),  // input wire [7 : 0] addrb
    .dinb(),    // input wire [18 : 0] dinb
    .doutb(ram_accu_rddata)  // output wire [18 : 0] doutb
);

/直方图均衡化
reg [26:0] data_mult;       //乘法运算结果
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        data_mult<=27'd0;
    else
        data_mult<=ram_accu_rddata*(IMG_MAX_GRAY-1);
end

reg [7:0] data_div;    //除法运算结果
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        data_div<=8'd0;
    else
        data_div<=data_mult/IMG_TOTAL_PIXEL;
end
//------------------------------------------
//lag 3 clocks signal sync  
reg	[2:0]	per_frame_vsync_r;
reg	[2:0]	per_frame_href_r;	
reg	[2:0]	per_frame_clken_r;
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
		per_frame_vsync_r <= 0;
		per_frame_href_r <= 0;
		per_frame_clken_r <= 0;
		end
	else
		begin
		per_frame_vsync_r 	<= 	{per_frame_vsync_r[1:0], 	per_frame_vsync};
		per_frame_href_r 	<= 	{per_frame_href_r[1:0], 	per_frame_href};
		per_frame_clken_r 	<= 	{per_frame_clken_r[1:0], 	per_frame_clken};
		end
end
assign	post_frame_vsync 	= 	per_frame_vsync_r[2];
assign	post_frame_href 	= 	per_frame_href_r[2];
assign	post_frame_clken 	= 	per_frame_clken_r[2];
assign  post_img_Y          =   post_frame_href?data_div:8'd0;
endmodule

5、结果图

6、参考资料

https://blog.csdn.net/qq_32010099/article/details/123060197

https://www.bilibili.com/video/BV1JV411J7ef/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=8b552433c6e99d96c09feffd0ad1ed7a

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值