基于FPGA的图像处理3--直方图操作IP的设计

Github:https://github.com/zgw598243565/HistogramCnt

3.1 灰度直方图统计

灰度直方图描述了一幅图像的灰度级统计信息,主要应用于图像分割,图像增强及图像灰度变化等处理过程。

        从数学上来说,图像直方图描述的图像各个灰度级的统计特性,它是用灰度值的一个函数来统计一幅图像中各个灰度级出现的次数或频率,其数学定义如下所示: 

        图像的直方图中往往包含很多有效的信息,一个很明显的信息就是图像的亮度和对比度信息。若图像亮度较亮,则图像的直方图统计主要峰值偏向右侧分布;若图像较暗,则图像的直方图统计主要峰值偏向左侧分布;若图像对比度较大,则直方图分布应该相对比较均匀;若图像对比度较小,则图像直方图分布应该相对比较集中。 

图 1 

        图1所示为灰度直方图统计电路的结构。该电路的设计思想是以像素值为地址,作为A端口的读写地址,将A端口读出的数据进行累加后,再通过A端口写入,以此达到相同灰度值累加,不同灰度值统计的功能。B端口则是用于外部对灰度统计直方图最后统计值的读取,clear信号表示在读取某一灰度值的统计信息后,是否将其清零,clear信号为高有效。但是,这样设计的灰度直方图统计电路结构存在一个Bug,那就是当输入是相邻的像素灰度值相同的时候,将会产生通过A端口对RAM中相同地址进行读写的操作,这时,应该读出之前写入的值进行累加,出现了写后读的时序错误,将会使相邻像素值个数的统计值减半。解决这个Bug的方法(我能想到的)是使用相同像素检测电路,将相邻的相同像素值自增,在检测到不同像素时再写入RAM中,这样可以避免同时读写RAM中的相同地址的存储单元,以此解决写后读的问题。

        灰度统计直方图的verilog实现方式如下所示。

module Histogram #(
    parameter PIXEL_WIDTH = 8,
    parameter IMAGE_WIDTH = 640,
    parameter IMAGE_HEIGHT = 480,
    parameter COLOR_RANGE = 256
)(clk,arstn,pixel_in,pixel_valid,data_out,dout_valid,dout_addr,dout_rreq,clear);

function integer clogb2(input integer bit_depth);
    begin
        for(clogb2 = 0;bit_depth >0; clogb2 = clogb2 + 1)
            bit_depth = bit_depth >> 1;
    end
endfunction

localparam TOTAL_PIXEL = IMAGE_WIDTH*IMAGE_HEIGHT;
localparam DATA_WIDTH = clogb2(TOTAL_PIXEL - 1);
localparam ADDRESS_WIDTH = clogb2(COLOR_RANGE - 1);

input clk;
input arstn;
input [PIXEL_WIDTH-1:0]pixel_in;
input pixel_valid;
output [DATA_WIDTH-1:0]data_out;
output dout_valid;
input [ADDRESS_WIDTH-1:0]dout_addr;
input dout_rreq;
input clear;
reg [PIXEL_WIDTH-1:0]pixel_in_delay;
reg pixel_valid_delay;
wire [DATA_WIDTH-1:0]inc_data;
wire [DATA_WIDTH-1:0]data_out_A;
wire dvalid_A;
wire mode;
assign inc_data = data_out_A + 1'b1;

always@(posedge clk or negedge arstn)
    begin
        if(~arstn)
            pixel_in_delay <= 0;
        else
            pixel_in_delay <= pixel_in;
    end

always@(posedge clk or negedge arstn)
    begin
        if(~arstn)
            pixel_valid_delay <= 0;
        else
            pixel_valid_delay <= pixel_valid;
    end 


Histogram_Ram #(
    .PIXEL_WIDTH(PIXEL_WIDTH),
    .IMAGE_WIDTH(IMAGE_WIDTH),
    .IMAGE_HEIGHT(IMAGE_HEIGHT),
    .COLOR_RANGE(COLOR_RANGE)
) Inst_ram(
    .clk(clk),
    .arstn(arstn),
    .read_addr_A(pixel_in),
    .read_data_A(data_out_A),
    .rvalid_A(pixel_valid),
    .dvalid_A(dvalid_A),
    .write_addr_A(pixel_in_delay),
    .write_data_A(inc_data),
    .wvalid_A(pixel_valid_delay),
    .read_addr_B(dout_addr),
    .read_data_B(data_out),
    .rvalid_B(dout_rreq),
    .dvalid_B(dout_valid),
    .clear(clear)
);
endmodule

3.2 灰度累计直方图统计 

        另一种典型并且使用广泛的直方图操作叫做灰度累计直方图,该操作是再灰度统计直方图的基础上进行统计。其数学定义如下所示:

        其中f(x)为灰度统计直方图的函数。 

        灰度累计直方图可以被用于灰度概率统计图,直方图均衡化,直方图规定化,直方图拉伸等计算。

1.灰度概率统计图(直方图概率密度函数)

         在实际应用中常常会用到归一化的直方图。假定一幅图像的像素总数为N,灰度级总数为L,其中灰度级为g的像素总数为Ng。用总像素N除各个灰度值出现的次数Ng,即可得到各个灰度级出现的概率,其数学定义如下:

2. 直方图均衡化

        直方图均衡化又称为灰度均衡化,是指通过某种灰度映射使输入图像转换为在每一灰度级上都有近似相同的输出图像(即输出的直方图是均匀的)。在经过均衡化处理后的图像中,像素将占有尽可能多的灰度级并且分布均匀。因此,这样的图像将具有较高的对比度和较大的动态范围。直方图均衡可以很好地解决相机过曝光或曝光不足的问题。对于离散灰度级,直方图均衡化的转换公式如下:

         上式中,H(i)为第i级灰度的像素个数,为第i级灰度的累计直方图的值,A0为图像的面积,也就是像素总个数,Dmax为最大灰度值(对于灰度图像就是255)。

3.直方图规定化

        直方图均衡化可以自动确定灰度变换函数,从而获得具有均匀直方图的输出图像。它主要用于增强动态范围较小的图像对比度,丰富图像的灰度级。这种方法的优点是操作简单,且结果可以预知,当图像需要自动增强时是一种不错的选择。

        在某种情况下,我们可能需要人为地控制直方图的形状,即我们希望获得具有指定直方图输出的图像,这样就可以有选择地增强某个灰度范围内的对比度或者使图像灰度值满足某种特定的分布。这种用于产生具有特定直方图的图像的方法称为直方图规定化。

        直方图规定化是在运用均衡化原理的基础上,通过建立原始图像和期望图像(待匹配直方图的图像)之间的关系,使原始图像的直方图匹配特定的形状,从而弥补了直方图均衡化不具备交互作用的特性。

4. 直方图拉伸

         在视频处理中,为了能够实时调节图像的对比度,通常需要对直方图进行拉伸处理。直方图拉伸是指将图像灰度直方图较窄的灰度级区间向两端拉伸,增强整幅图像像素的灰度级对比度,达到增强图像的效果。

         常见的直方图拉伸方法有线性拉伸,3段式分段线性拉伸和非线性拉伸等。线性拉伸也即灰度拉伸,属于线性点运算的一种。它扩展图像的直方图,使其充满整个灰度级范围内。

        设f(x,y)为输入图像,它的最小灰度级A和最大灰度级B的定义如下: 

         将A和B分别映射到0和255,则最终得到输出图像g(x,y)为:

        线性拉伸能达到类似于直方图均衡化的功能,将比较集中的直方图拉伸到整个灰度分布区域。但是,在实际应用中,并不会采用上述的拉伸方式,主要是基于噪声考虑。为了解决这个问题,一种比较常用的处理方法是基于直方图统计的线性拉伸。此种方法不是简单地用整幅图像的最高灰度值和最低灰度值来计算拉伸系统A和B,而是基于直方图统计信息来进行计算。计算步骤如下: 

 (1) 首先进行直方图统计计算,规定灰度值为i的统计结果为H(i)。

 (2) 计算直方图统计累加和Sum(k),定义如下:

 (3) 设定两个阈值Thr_Min和Thr_Max,拉伸系数A和B的定义如下:

         如何处理落在阶段区间外的像素值,最简单的办法是,对小于左侧区间的,置0 处理,对大于右侧区间的,置1处理。计算公式如下:

由定义可知,该拉伸运算直接截取直方图”有效”区间进行拉伸,可大大减小噪声干扰。 

 

 图 2

        图2所示为灰度累计直方图的电路结构,该结构中主要由三部分组成,第一个是用于存储统计累加结果值的RAM,第二个是用进行值累加的累加电路Accumulator,第三个是用于产生对统计直方图结果进行访存的地址控制器Addr_Controller。灰度累计直方图的具体实现如下所示。

module HistAccmulator #(
     parameter IMAGE_WIDTH = 640,
     parameter IMAGE_HEIGHT = 480,
     parameter COLOR_RANGE = 256
)
(clk,arstn,data_in,data_valid,addr,addr_valid,start,data_out,dout_valid,raddr,raddr_valid,clear,done);


function integer clogb2(input integer bit_depth);
    begin
        for(clogb2 = 0;bit_depth > 0;clogb2 = clogb2 + 1)
            bit_depth = bit_depth >> 1;
    end
endfunction

localparam TOTAL_PIXEL = IMAGE_WIDTH*IMAGE_HEIGHT;
localparam DATA_WIDTH = clogb2(TOTAL_PIXEL - 1);
localparam ADDRESS_WIDTH = clogb2(COLOR_RANGE - 1);

input clk;
input arstn;
input [DATA_WIDTH-1:0]data_in;
input data_valid;
output [ADDRESS_WIDTH-1:0]addr;
output addr_valid;
input start;
output [DATA_WIDTH-1:0]data_out;
output dout_valid;
input [ADDRESS_WIDTH-1:0]raddr;
input raddr_valid;
input clear;
output done;
wire [DATA_WIDTH-1:0]acculator_out;
wire wreq;
wire adder_done;
Accumulator #(
    .DATA_WIDTH(DATA_WIDTH)
)Inst_accumulator(
    .clk(clk),
    .arstn(arstn),
    .data_in(data_in),
    .data_valid(data_valid),
    .data_out(acculator_out),
    .clear(done)
);

Addr_Controller #(
    .ADDRESS_WIDTH(ADDRESS_WIDTH),
    .COLOR_RANGE(256)
)Inst_adder_comtroller(
    .clk(clk),
    .arstn(arstn),
    .start(start),
    .done(adder_done),
    .addr(addr),
    .addr_valid(addr_valid),
    .wreq(wreq)
);

reg [ADDRESS_WIDTH-1:0]addr_dely0;
reg [ADDRESS_WIDTH-1:0]addr_dely1;
reg wreq_dely0;
reg wreq_dely1;
reg done_dely0;
reg done_dely1;


always@(posedge clk or negedge arstn)
    begin
        if(~arstn)
            begin
                addr_dely0 <= 0;
                addr_dely1 <= 0;
                wreq_dely0 <= 0;
                wreq_dely1 <= 0;
                done_dely0 <= 0;
                done_dely1 <= 0;
            end
        else
            begin
                addr_dely0 <= addr;
                addr_dely1 <= addr_dely0;
                wreq_dely0 <= wreq;
                wreq_dely1 <= wreq_dely0;
                done_dely0 <= done;
                done_dely1 <= done_dely0;
            end
    end
assign done = done_dely1;

Accumulator_Ram #(
    .DATA_WIDTH(DATA_WIDTH),
    .DATA_DEPTH(COLOR_RANGE)
)Inst_accumulatorram(
    .clk(clk),
    .arstn(arstn),
    .write_addr_A(addr_dely1),
    .write_data_A(acculator_out),
    .wvalid_A(wreq_dely1),
    .read_addr_A(raddr),
    .read_data_A(data_out),
    .rvalid_A(raddr_valid),
    .dvalid_A(dout_valid),
    .clear(clear)
);
endmodule

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值