失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > FPGA图像处理基础----直方图均衡化

FPGA图像处理基础----直方图均衡化

时间:2024-09-16 07:30:35

相关推荐

FPGA图像处理基础----直方图均衡化

啥是直方图均衡化

直方图均衡化,通过一种灰度映射使输入图像经过转换后,在每一灰度级上都有相近似的输出图像,输出的灰度值是均匀的。经过这样处理的图像具有较高的对比对和较大的动态范围。

对于离散的灰度级,直方图均衡化有如下关系:

其中Db是转换过后的像素的灰度值,Dmax是输入图像经过直方图统计后得到的最大的灰度值,A0是一幅图像面积,也就是所有的像素值H(i)是灰度级的各级的统计结果。Da是当前像素的灰度级。

直方图均衡化就的作用就是,对于当前的输入像素,需要首先求出小于当前像素灰度值的所有像素统计值的和,然后与该图像中的最大灰度值进行相乘,最后除以图像的面积。

基于FPGA的直方图均衡化

基于FPGA也是能够完成图像的直方图的处理的。具体的计算步骤如下:

首先需要统计出该图像的直方图分布H(i)其次需要计算出各个灰度级下的直方图累加和也即

找到图像的灰度最大值Dmax,然后将Dmax与对应灰度级的累加和相乘除以总的像素面积,完成图像直方图的转换

在本人进行算法验证的时候,并没有对输入图像进行帧缓存,正常的操作应该是,将本帧的直方图统计完成后,在将缓存好的图像从内存中取出,并进行直方图均衡化。在进行算法验证时,未进行帧缓存,相当于将上一帧图像数据的统计结果作为下一帧图像的变换因子。这在变化速率不太快的情况下是可以采取的一种方式。

具体实现过程

1. 求累加和

在上一篇博客中介绍了图像直方图的统计方法,并且最终得到的输出的直方图统计值和有效信号。因此上游模块输出直方图统计信息时,可以进行计算直方图对应灰度级下的累加和,并且确定灰度的最大值。

采用一个BRAM来存储一幅图像的灰度累加和。于此同时确定当前图形中的灰度最大值。

2. 进行乘法计算

在上一步求得灰度累加和之后,当前帧图像像素已经来临,因此可以将该像素对应的灰度级和最大灰度值相乘。由于FPGA并不擅长乘法运算,尤其不擅长除法运算。因此在进行乘除法时,会调用内部的专用的DSP资源,因此可以调用Xilinx的乘法器或者除法器IP来进行乘除法的运算。

在进行乘法运算时,需要根据仿真的结果来确定乘法的Latency。

3. 进行除法计算

在上一步的乘法计算完成后,可以进行除法的运算,在除法IP的配置时,可以设置除法的运算的潜伏期。本人所设置的Latency为7。

代码设计

/*============================================## Author: Wcc - 1530604142@## QQ : 1530604142## Last modified: -07-08 20:02## Filename: histogram_equalization.v## Description: #============================================*/`timescale 1ns / 1psmodule histogram_equalization(inputwire clk,inputwire rst,input wire pi_hsync,//输入的视频流信号inputwire pi_vsync,input wirepi_de ,inputwire pi_data_vld,input wire [7:0]pi_data ,input wire pi_histo_vld,//输入的直方图统计信息input wire [31:0]pi_histo_data,output wire po_hsync,//输出的视频流信号outputwire po_vsync,outputwirepo_de,outputwire po_data_vld,output wire [7:0]po_data );//==========================================//parameter define//==========================================parameter IMG_WIDTH = 128 ;parameter IMG_HEIGHT =128 ;localparam TOTAL_PIXEL= IMG_WIDTH * IMG_HEIGHT;//==========================================//internal signal//==========================================reg [1:0]vsync_dd;//场同步信号延时reg [7:0]pi_data_dd;//输入数据延时reg data_vld_dd;//输入数据有效延时reg [2:0]stream_vld_dd;//==========================================//求累加和与找寻灰度最大最小值//==========================================reg [31:0]gray_sum ;//灰度累加和reg [7:0]gray_max ;//灰度值最大值reg [7:0]gray_min ;//灰度值最小值reg [7:0]gray_idx;//灰度值索引//==========================================//确定当前像素在图像中的位置//==========================================reg [12:0]cnt_col ;wireadd_cnt_col ;wireend_cnt_col;reg [12:0]cnt_row ;wireend_cnt_row;wireadd_cnt_row ;//==========================================//ram 相关//==========================================reg wr_ram_en;//存储灰度累加和的RAMwire [31:0]wr_ram_data ;//写入RAM的数据reg [7:0]wr_ram_addr;//写RAM时的地址wire[7:0]rd_ram_addr;wire[31:0]rd_ram_data;//==========================================//multiplier//==========================================wire [39:0]mult_value;//乘积wire mult_vld ;//乘积有效信号//==========================================//divider//==========================================wire div_tvalid;wire [63 : 0] div_tdata;//----------------vsync_dd------------------always @(posedge clk) beginif (rst==1'b1) beginvsync_dd <= 'd0;endelse beginvsync_dd <= {vsync_dd[0], pi_vsync};endend//==========================================//将累加和写入到RAM中//==========================================//----------------gray_sum------------------always @(posedge clk) beginif (rst==1'b1) begingray_sum <= 'd0;endelse if (pi_histo_vld == 1'b1) begingray_sum <= gray_sum + pi_histo_data;endelse begingray_sum <= 'd0;endend//----------------wr_ram_data------------------assign wr_ram_data = gray_sum;//----------------wr_ram_en------------------always @(posedge clk) beginif (rst==1'b1) beginwr_ram_en <= 1'b0;endelse beginwr_ram_en <= pi_histo_vld;endend//----------------wr_ram_addr------------------always @(posedge clk) beginif (rst==1'b1) beginwr_ram_addr <= 'd0;endelse if (wr_ram_en == 1'b1) beginwr_ram_addr <= wr_ram_addr + 1'b1;endelse beginwr_ram_addr <= 'd0;endend//==========================================//找寻最大最小值//==========================================//----------------gray_indx------------------always @(posedge clk) beginif (rst==1'b1) begingray_idx <= 'd0;endelse if (pi_histo_vld == 1'b1) begingray_idx <= gray_idx + 1'b1;endelse begingray_idx <= 'd0;endend//----------------gray_max------------------always @(posedge clk) beginif (rst==1'b1) begingray_max <= 'd0;gray_min <= 'd255;end//检测到一帧图像结束else if (end_cnt_row == 1'b1) begingray_max <= 'd0;gray_min <= 'd255;endelse if (pi_histo_data != 0 && pi_histo_vld == 1'b1 ) beginif (gray_max <= gray_idx) begingray_max <= gray_idx;endif (gray_min >= gray_idx) begingray_min <= gray_idx;endendend//----------------pi_data_dd, data_vld_dd------------------always @(posedge clk) beginif (rst==1'b1) beginpi_data_dd <= 'd0;data_vld_dd <= 'd0;endelse beginpi_data_dd <= pi_data;data_vld_dd <= pi_data_vld;endend//----------------stream_vld_dd------------------always @(posedge clk) beginif (rst==1'b1) beginstream_vld_dd <= 'd0;endelse beginstream_vld_dd <= {stream_vld_dd[1:0], data_vld_dd};endendassign mult_vld = stream_vld_dd[2];//----------------rd_ram_addr------------------assign rd_ram_addr = (pi_data_vld) ? pi_data : 'd0;sum_ram inst_sum_ram (.clka(clk), // input wire clka.wea(wr_ram_en),// input wire [0 : 0] wea.addra(wr_ram_addr), // input wire [7 : 0] addra.dina(wr_ram_data), // input wire [31 : 0] dina.clkb(clk), // input wire clkb.addrb(rd_ram_addr), // input wire [7 : 0] addrb.doutb(rd_ram_data) // output wire [31 : 0] doutb);//==========================================//乘法器 3个时钟周期的潜伏期//==========================================mul_graylevel int_multiplier (.CLK(clk), // input wire CLK.A(gray_max),// input wire [7 : 0] A.B(rd_ram_data), // input wire [31 : 0] B.P(mult_value) // output wire [39 : 0] P);//==========================================//除法器 7个时钟周期的Latency//==========================================// m_axis_dout_tdata[63 : 0 ]//[63:24] 商//[21:0] 余数div_gray inst_divider (.aclk(clk), // input wire aclk.s_axis_divisor_tvalid(1'b1), // input wire s_axis_divisor_tvalid.s_axis_divisor_tdata(TOTAL_PIXEL[23:0]),// input wire [23 : 0] s_axis_divisor_tdata.s_axis_dividend_tvalid(mult_vld), // input wire s_axis_dividend_tvalid.s_axis_dividend_tdata(mult_value), // input wire [39 : 0] s_axis_dividend_tdata.m_axis_dout_tvalid(div_tvalid),// output wire m_axis_dout_tvalid.m_axis_dout_tdata(div_tdata) // output wire [63 : 0] m_axis_dout_tdata);assign po_data_vld = div_tvalid;//==========================================//确定当前像素在图像中的位置//==========================================//----------------cnt_col------------------always @(posedge clk) beginif (rst == 1'b1) begincnt_col <= 'd0;endelse if (add_cnt_col) beginif(end_cnt_col)cnt_col <= 'd0;elsecnt_col <= cnt_col + 1'b1;endelse begincnt_col <= 'd0;endendassign add_cnt_col = div_tvalid == 1'b1;assign end_cnt_col = add_cnt_col &&cnt_col == IMG_WIDTH - 1;//----------------cnt_row------------------always @(posedge clk) beginif (rst == 1'b1) begincnt_row <= 'd0;endelse if (add_cnt_row) beginif(end_cnt_row)cnt_row <= 'd0;elsecnt_row <= cnt_row + 1'b1;endendassign add_cnt_row = end_cnt_col;assign end_cnt_row = add_cnt_row &&cnt_row == IMG_HEIGHT - 1;//----------------pi_hsync_dd/pi_vsync_dd,pi_de_dd------------------reg [10:0]pi_hsync_dd;reg [10:0]pi_vsync_dd;reg [10:0]pi_de_dd;reg [87:0]data_dd ;//从数据输出到输出共有11个时钟周期的latencyalways @(posedge clk) beginif (rst==1'b1) beginpi_hsync_dd <= 'd0;pi_vsync_dd <= 'd0;pi_de_dd <= 'd0;data_dd <= 'd0;endelse beginpi_hsync_dd <= {pi_hsync_dd[9:0], pi_hsync};pi_vsync_dd <= {pi_vsync_dd[9:0], pi_vsync};pi_de_dd <= {pi_de_dd[9:0], pi_de};data_dd <= {data_dd[79:0], pi_data};endendassign po_hsync = pi_hsync_dd[10];assign po_vsync = pi_vsync_dd[10];assign po_de = pi_de_dd[10];assign po_data = (po_data_vld) ? div_tdata[31:24] : data_dd[87:80];endmodule

测试结果

在片内存储中,存储有一幅灰度图像的信息,下面的两幅图像中,第一幅图像是经过直方图均衡化过后的结果,第一幅图像的对比度相较于第二幅要高。

参考:《基于FPGA的数字图像处理》牟新刚

如果觉得《FPGA图像处理基础----直方图均衡化》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。