FPGA图像处理之直方图均衡实现

编程入门 行业动态 更新时间:2024-10-27 21:19:49

FPGA图像处理之<a href=https://www.elefans.com/category/jswz/34/1763343.html style=直方图均衡实现"/>

FPGA图像处理之直方图均衡实现

FPGA图像处理之直方图均衡实现

1. 直方图均衡的原理

直方图均衡的基本原理,就是对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行拉伸,而对像素个数较少的灰度值(即对画面不起主要作用的灰度值)进行合并,从而提高对比度,使图像清晰,达到增强的目的。


为了将原图像的亮度范围进行扩展, 需要一个映射函数, 将原图像的像素值均衡映射到新直方图中, 这个映射函数有两个条件:

  1. 不能打乱原有的像素值大小顺序, 映射后亮、 暗的大小关系不能改变;
  2. 映射后必须在原有的范围内,即像素映射函数的值域应在0和255之间;

综合以上两个条件,累积分布函数是个好的选择,因为累积分布函数是单调增函数(控制大小关系),并且值域是0到1(控制越界问题),所以直方图均衡化中使用的是累积分布函数。

2. 直方图均衡的FPGA实现

根据直方图均衡的功能将其划分为两个子模块,分别为hist_stat模块和histEQ_proc模块,直方图均衡FPGA设计框架,如图1所示。hist_stat模块的功能是进行像素的灰度级数统计和灰度级数累积统计;histEQ_proc模块的功能是对原始图像进行直方图均衡。
直方图均衡的业务处理流程如下。
(1)将原始图像输入到hist_stat模块进行像素灰度级数统计和灰度级数累计统计,同时原始图像存储于外部存储器。
(2)在(1)完成后,histEQ_proc模块从外部存储器读取原始图像进行直方图均衡,输出增强后的图像。

3. FPGA 代码实现

1.外部存储器模块

module bram_ture_dual_port
#(parameter C_ADDR_WIDTH  = 8,parameter C_DATA_WIDTH  = 8
)(input  wire                     clka    ,input  wire                     wea     ,input  wire [C_ADDR_WIDTH-1:0]  addra   ,input  wire [C_DATA_WIDTH-1:0]  dina    ,output reg  [C_DATA_WIDTH-1:0]  douta   ,input  wire                     clkb    ,input  wire                     web     ,input  wire [C_ADDR_WIDTH-1:0]  addrb   ,input  wire [C_DATA_WIDTH-1:0]  dinb    ,output reg  [C_DATA_WIDTH-1:0]  doutb   
);
//----------------------------------------------------------------------
localparam C_MEM_DEPTH = {C_ADDR_WIDTH{1'b1}};reg     [C_DATA_WIDTH-1:0]      mem [C_MEM_DEPTH:0];
integer                         i;initial
beginfor(i = 0;i <= C_MEM_DEPTH;i = i+1)mem[i] = 0;
end always @(posedge clka)
beginif(wea == 1'b1)mem[addra] <= dina; elsedouta <= mem[addra];
endalways @(posedge clkb)
beginif(web == 1'b1)mem[addrb] <= dinb; elsedoutb <= mem[addrb];
endendmodule

2.hist_stat模块

module hist_stat
(input  wire                 clk                 ,input  wire                 rst_n               ,input  wire                 img_vsync           ,input  wire                 img_href            ,input  wire     [ 7:0]      img_gray            ,output reg      [ 7:0]      pixel_level         ,output reg      [19:0]      pixel_level_acc_num ,output reg                  pixel_level_valid   
);
//----------------------------------------------------------------------
//  bram signals define
wire                            bram_a_wenb;
wire            [ 7:0]          bram_a_addr;
wire            [19:0]          bram_a_rdata;
wire                            bram_b_wenb;
wire            [ 7:0]          bram_b_addr;
wire            [19:0]          bram_b_wdata;
wire            [19:0]          bram_b_rdata;//----------------------------------------------------------------------
//  preprocess
reg             [7:0]           pixel_data;always @(posedge clk)
beginpixel_data <= img_gray;
endreg                             pixel_data_valid;always @(posedge clk or negedge rst_n)
beginif(!rst_n)pixel_data_valid <= 1'b0;elsepixel_data_valid <= img_href;
endreg                             img_vsync_dly;always @(posedge clk or negedge rst_n)
beginif(!rst_n)img_vsync_dly <= 1'b0;elseimg_vsync_dly <= img_vsync;
endwire                            pixel_data_eop;
assign pixel_data_eop = img_vsync_dly & ~img_vsync;//----------------------------------------------------------------------
//  preprocess
reg             [7:0]           pixel_data_tmp;always @(posedge clk)
beginpixel_data_tmp <= pixel_data;
endreg                             pixel_data_valid_tmp1;always @(posedge clk or negedge rst_n)
beginif(!rst_n)pixel_data_valid_tmp1 <= 1'b0;elsebeginif(pixel_data_valid == 1'b1)beginif(pixel_data_valid_tmp1 == 1'b0)pixel_data_valid_tmp1 <= 1'b1;elsebeginif(pixel_data_tmp == pixel_data)pixel_data_valid_tmp1 <= 1'b0;elsepixel_data_valid_tmp1 <= 1'b1;endendelsepixel_data_valid_tmp1 <= 1'b0;end
endreg             [1:0]           pixel_data_cnt_tmp;always @(posedge clk or negedge rst_n)
beginif(!rst_n)pixel_data_cnt_tmp <= 2'd1;elsebeginif((pixel_data_valid == 1'b1)&&(pixel_data_valid_tmp1 == 1'b1)&&(pixel_data_tmp == pixel_data))pixel_data_cnt_tmp <= 2'd2;elsepixel_data_cnt_tmp <= 2'd1;end
endreg                             pixel_data_eop_tmp;always @(posedge clk or negedge rst_n)
beginif(!rst_n)pixel_data_eop_tmp <= 1'b0;elsepixel_data_eop_tmp <= pixel_data_eop;
end//----------------------------------------------------------------------
//  c1
reg             [7:0]           pixel_data_c1;always @(posedge clk)
beginpixel_data_c1 <= pixel_data;
endreg                             pixel_data_eop_c1;
reg                             pixel_data_valid_tmp_c1;always @(posedge clk or negedge rst_n)
beginif(!rst_n)beginpixel_data_eop_c1       <= 1'b0;pixel_data_valid_tmp_c1 <= 1'b0;endelsebeginpixel_data_eop_c1       <= pixel_data_eop_tmp;pixel_data_valid_tmp_c1 <= pixel_data_valid_tmp1;end
end//----------------------------------------------------------------------
//  c2 : delay 3 clock
reg             [7:0]           pixel_data_c2;always @(posedge clk)
beginpixel_data_c2 <= pixel_data_c1;
endreg                             pixel_data_eop_tmp1_c2;
reg                             pixel_data_eop_tmp2_c2;
reg                             pixel_data_eop_c2;always @(posedge clk or negedge rst_n)
beginif(!rst_n)beginpixel_data_eop_tmp1_c2 <= 1'b0;pixel_data_eop_tmp2_c2 <= 1'b0;pixel_data_eop_c2      <= 1'b0;endelsebeginpixel_data_eop_tmp1_c2 <= pixel_data_eop_c1;pixel_data_eop_tmp2_c2 <= pixel_data_eop_tmp1_c2;pixel_data_eop_c2      <= pixel_data_eop_tmp2_c2;end
end//----------------------------------------------------------------------
//  c3
reg                             bram_rw_ctrl_flag_c3;
reg             [8:0]           bram_rw_ctrl_cnt;always @(posedge clk or negedge rst_n)
beginif(!rst_n)bram_rw_ctrl_flag_c3 <= 1'b0;elsebeginif(pixel_data_eop_c2 == 1'b1)bram_rw_ctrl_flag_c3 <= 1'b1;else if(bram_rw_ctrl_cnt == 9'h100)bram_rw_ctrl_flag_c3 <= 1'b0;elsebram_rw_ctrl_flag_c3 <= bram_rw_ctrl_flag_c3;end
endreg             [8:0]           bram_rw_ctrl_cnt_dly;always @(posedge clk)
beginbram_rw_ctrl_cnt_dly <= bram_rw_ctrl_cnt;
endalways @(*)
beginif(bram_rw_ctrl_flag_c3 == 1'b1)bram_rw_ctrl_cnt <= bram_rw_ctrl_cnt_dly + 1'b1;elsebram_rw_ctrl_cnt <= 9'b0;
endwire            [7:0]           bram_addr_c3;
assign bram_addr_c3 = bram_rw_ctrl_cnt - 1'b1;//----------------------------------------------------------------------
//  c4
reg                             bram_rw_ctrl_flag_c4;always @(posedge clk or negedge rst_n)
beginif(!rst_n)bram_rw_ctrl_flag_c4 <= 1'b0;elsebram_rw_ctrl_flag_c4 <= bram_rw_ctrl_flag_c3;
endreg             [7:0]           bram_addr_c4;always @(posedge clk)
beginbram_addr_c4 <= bram_addr_c3;
end//----------------------------------------------------------------------
//  c5
reg             [7:0]           pixel_level_c5;always @(posedge clk)
beginpixel_level_c5 <= bram_addr_c4;
endreg             [19:0]          pixel_level_num_c5;always @(posedge clk)
beginif(bram_rw_ctrl_flag_c4 == 1'b1)pixel_level_num_c5 <= bram_b_rdata;elsepixel_level_num_c5 <= 20'b0;
endreg                             pixel_level_valid_c5;always @(posedge clk or negedge rst_n)
beginif(!rst_n)pixel_level_valid_c5 <= 1'b0;elsepixel_level_valid_c5 <= bram_rw_ctrl_flag_c4;
end//----------------------------------------------------------------------
//  c6
reg             [7:0]           pixel_level_c6;always @(posedge clk)
beginpixel_level_c6 <= pixel_level_c5;
endreg             [19:0]          pixel_level_acc_num_c6;always @(posedge clk)
beginif(pixel_level_valid_c5 == 1'b1)beginif(pixel_level_c5 == 8'b0)pixel_level_acc_num_c6 <= pixel_level_num_c5;elsepixel_level_acc_num_c6 <= pixel_level_acc_num_c6 + pixel_level_num_c5;endelsepixel_level_acc_num_c6 <= pixel_level_acc_num_c6;
endreg                             pixel_level_valid_c6;always @(posedge clk or negedge rst_n)
beginif(!rst_n)pixel_level_valid_c6 <= 1'b0;elsepixel_level_valid_c6 <= pixel_level_valid_c5;
end//----------------------------------------------------------------------
//  signal output
always @(posedge clk)
beginpixel_level         <= pixel_level_c6;pixel_level_acc_num <= pixel_level_acc_num_c6;
endalways @(posedge clk or negedge rst_n)
beginif(!rst_n)pixel_level_valid <= 1'b0;elsepixel_level_valid <= pixel_level_valid_c6;
end//----------------------------------------------------------------------
//  bram_a20d256_b20d256 module initialization
assign bram_a_wenb  = bram_rw_ctrl_flag_c4;
assign bram_a_addr  = (bram_rw_ctrl_flag_c4 == 1'b1) ? bram_addr_c4 : pixel_data_tmp;
assign bram_b_wenb  = pixel_data_valid_tmp_c1;
assign bram_b_addr  = (bram_rw_ctrl_flag_c3 == 1'b1) ? bram_addr_c3 : pixel_data_c2;
assign bram_b_wdata = bram_a_rdata + pixel_data_cnt_tmp;bram_ture_dual_port
#(.C_ADDR_WIDTH   (8 ),.C_DATA_WIDTH   (20)
)
u_bram_ture_dual_port
(.clka   (clk            ),.wea    (bram_a_wenb    ),.addra  (bram_a_addr    ),.dina   (20'b0          ),.douta  (bram_a_rdata   ),.clkb   (clk            ),.web    (bram_b_wenb    ),.addrb  (bram_b_addr    ),.dinb   (bram_b_wdata   ),.doutb  (bram_b_rdata   )
);endmodule

3.histEQ_proc模块

module histEQ_proc
(input  wire                 clk                 ,input  wire                 rst_n               ,input  wire     [ 7:0]      pixel_level         ,input  wire     [19:0]      pixel_level_acc_num ,input  wire                 pixel_level_valid   ,output reg                  histEQ_start_flag   ,input  wire                 per_img_vsync       ,input  wire                 per_img_href        ,input  wire     [ 7:0]      per_img_gray        ,output wire                 post_img_vsync      ,output wire                 post_img_href       ,output wire     [ 7:0]      post_img_gray       
);
//----------------------------------------------------------------------
//  delay 1 clock
wire                            bram_a_wenb;
wire            [ 7:0]          bram_a_addr;
wire            [19:0]          bram_a_wdata;
wire            [ 7:0]          bram_b_addr;
wire            [19:0]          bram_b_rdata;assign bram_a_wenb  = pixel_level_valid;
assign bram_a_addr  = pixel_level;
assign bram_a_wdata = pixel_level_acc_num;
assign bram_b_addr  = per_img_gray;bram_ture_dual_port
#(.C_ADDR_WIDTH   (8 ),.C_DATA_WIDTH   (20)
)
u_bram_ture_dual_port
(.clka   (clk            ),.wea    (bram_a_wenb    ),.addra  (bram_a_addr    ),.dina   (bram_a_wdata   ),.douta  (               ),.clkb   (clk            ),.web    (1'b0           ),.addrb  (bram_b_addr    ),.dinb   (20'b0          ),.doutb  (bram_b_rdata   )
);always @(posedge clk or negedge rst_n)
beginif(!rst_n)histEQ_start_flag <= 1'b0;elsebeginif((pixel_level_valid == 1'b1)&&(pixel_level == 8'd255))histEQ_start_flag <= 1'b1;elsehistEQ_start_flag <= 1'b0;end
end//----------------------------------------------------------------------
//  uint8(CumPixel/980) = round(CumPixel * 136957/2^27) , CumPixel <= 500*500
reg             [34:0]          mult_result;always @(posedge clk)
beginmult_result <= bram_b_rdata * 18'd136957;
endreg             [7:0]           pixel_data;always @(posedge clk)
beginpixel_data <= mult_result[34:27] + mult_result[26];
end//----------------------------------------------------------------------
//  lag 3 clocks signal sync
reg             [2:0]           per_img_vsync_r;
reg             [2:0]           per_img_href_r;always @(posedge clk or negedge rst_n)
beginif(!rst_n)beginper_img_vsync_r <= 3'b0;per_img_href_r  <= 3'b0;endelsebeginper_img_vsync_r <= {per_img_vsync_r[1:0],per_img_vsync};per_img_href_r  <= {per_img_href_r[1:0],per_img_href};end
end//----------------------------------------------------------------------
assign post_img_vsync = per_img_vsync_r[2];
assign post_img_href  = per_img_href_r[2];
assign post_img_gray  = pixel_data;endmodule

4.参考资料

1.基于MATLAB与FPGA的图像处理教程(韩彬)
2.

更多推荐

FPGA图像处理之直方图均衡实现

本文发布于:2024-02-25 18:41:11,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1699924.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:直方图   图像处理   FPGA

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!