直方图统计原理
百度百科中关于直方图均衡化的描述:
图像处理领域中利用图像直方图对对比度进行调整的方法。 对比度是画面黑与白的比值,也就是从黑到白的渐变层次。比值越大,从黑到白的渐变层次就越多,从而色彩表现越丰富。对比度对视觉效果的影响非常关键,一般来说对比度越大,图像越清晰醒目,色彩也越鲜明艳丽;而对比度小,则会让整个画面都灰蒙蒙的。
直方图均衡化分为真均衡化和伪均衡化,由于FPGA不方便实现真均衡化,所以采用伪均衡化,即前一帧的图像进行统计、帧间隙进行累计和与归一化、当前帧做归一化后的映射输出。不过仿真的话,前一帧和当前帧是同一张图片,就是真均衡化。
下图是咸鱼fpga博客中直方图均衡化的波形图:
本人按照上图的思路实现,没有ram2的清零,因为ram2写入会覆盖旧数据。
直方图均衡化步骤:
- 第一帧统计直方图存入ram1
- 帧间隙读出ram1中数据进行计算,将计算结果存入ram2,同时对ram1进行清零
- 第二帧根据映射表进行输出
直方图统计
为了建立直方图,在FPGA中可以用256个计数器对每个灰度进行计数,不过这样做代码代码量太大,使用的资源也很多,不太现实。
像素是一个个来的,因此任何时钟周期都只有一个计数器在增加,意味着累加器可以在存储器中实现,首先需要读取相关存储单元,然后加一再写回,这需要用到双端口ram,一个读端口一个写端口。不过需要注意,因为读出数据需要一拍,图中灰度I需要打一拍再送入写入端口的地址端。
这种做法会有误差,因为ram在读写冲突时读出的是旧数据,所以当连续相同像素到来时,会出现统计丢失,不过对结果影响很小,视觉上难以辨别。本人水平有限,无法解决这个问题。
直方图均衡化
直方图均衡化公式:
H(i)为第 i 级灰度的像素个数,A0为图像的面积(即分辨率),Dmax为灰度最大值,即255。
帧间隙时,设计一个计数器,从0计数到255,将ram1中的数据读出来,同时对ram1进行清零。读出的数据会通过流水线计算,得出直方图均衡化后的灰度级映射,再写入ram2。第一级进行累加,第二级乘以255,第三级除以分辨率。
第二帧只需读出ram2中的数据进行映射输出即可得到直方图均衡化后的图像。
verilog代码
module histgram_equ(
input clk,
input rst_n,
// input
input pre_vsync,
input pre_href,
input pre_clken,
input [7:0] pre_img_Y,
// output
output reg post_vsync,
output reg post_href,
output reg post_clken,
output [7:0] post_img_Y
);
//----------------------信号声明--------------------------
// ram1读地址总线
wire [7:0] rd_addr_bus;
// ram1读数据
wire [31:0] rd_data;
// ram1写使能总线
wire wren_bus;
// ram1写地址总线
wire [7:0] wr_addr_bus;
// ram1写数据总线
wire [31:0] wr_data_bus;
// 输入灰度打一拍
reg [7:0