啥是直方图均衡化
直方图均衡化,通过一种灰度映射使输入图像经过转换后,在每一灰度级上都有相近似的输出图像,输出的灰度值是均匀的。经过这样处理的图像具有较高的对比对和较大的动态范围。
对于离散的灰度级,直方图均衡化有如下关系:
其中Db是转换过后的像素的灰度值,Dmax是输入图像经过直方图统计后得到的最大的灰度值,A0是一幅图像面积,也就是所有的像素值H(i)是灰度级的各级的统计结果。Da是当前像素的灰度级。
直方图均衡化就的作用就是,对于当前的输入像素,需要首先求出小于当前像素灰度值的所有像素统计值的和,然后与该图像中的最大灰度值进行相乘,最后除以图像的面积。
基于FPGA的直方图均衡化
基于FPGA也是能够完成图像的直方图的处理的。具体的计算步骤如下:
- 首先需要统计出该图像的直方图分布H(i)
- 其次需要计算出各个灰度级下的直方图累加和也即
- 找到图像的灰度最大值Dmax,然后将Dmax与对应灰度级的累加和相乘
- 除以总的像素面积,完成图像直方图的转换
在本人进行算法验证的时候,并没有对输入图像进行帧缓存,正常的操作应该是,将本帧的直方图统计完成后,在将缓存好的图像从内存中取出,并进行直方图均衡化。在进行算法验证时,未进行帧缓存,相当于将上一帧图像数据的统计结果作为下一帧图像的变换因子。这在变化速率不太快的情况下是可以采取的一种方式。
具体实现过程
1. 求累加和
在上一篇博客中介绍了图像直方图的统计方法,并且最终得到的输出的直方图统计值和有效信号。因此上游模块输出直方图统计信息时,可以进行计算直方图对应灰度级下的累加和,并且确定灰度的最大值。
采用一个BRAM来存储一幅图像的灰度累加和。于此同时确定当前图形中的灰度最大值。
2. 进行乘法计算
在上一步求得灰度累加和之后,当前帧图像像素已经来临,因此可以将该像素对应的灰度级和最大灰度值相乘。由于FPGA并不擅长乘法运算,尤其不擅长除法运算。因此在进行乘除法时,会调用内部的专用的DSP资源,因此可以调用Xilinx的乘法器或者除法器IP来进行乘除法的运算。
在进行乘法运算时,需要根据仿真的结果来确定乘法的Latency。
3. 进行除法计算
在上一步的乘法计算完成后,可以进行除法的运算,在除法IP的配置时,可以设置除法的运算的潜伏期。本人所设置的Latency为7。
代码设计
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312/*============================================ # # Author: Wcc - 1530604142@qq.com # # QQ : 1530604142 # # Last modified: 2020-07-08 20:02 # # Filename: histogram_equalization.v # # Description: # ============================================*/ `timescale 1ns / 1ps module histogram_equalization( input wire clk , input wire rst , input wire pi_hsync ,//输入的视频流信号 input wire pi_vsync , input wire pi_de , input wire 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 ,//输出的视频流信号 output wire po_vsync , output wire po_de , output wire 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 ; wire add_cnt_col ; wire end_cnt_col ; reg [12:0] cnt_row ; wire end_cnt_row ; wire add_cnt_row ; //========================================== //ram 相关 //========================================== reg wr_ram_en ;//存储灰度累加和的RAM wire [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) begin if (rst==1'b1) begin vsync_dd <= 'd0; end else begin vsync_dd <= {vsync_dd[0], pi_vsync}; end end //========================================== //将累加和写入到RAM中 //========================================== //----------------gray_sum------------------ always @(posedge clk) begin if (rst==1'b1) begin gray_sum <= 'd0; end else if (pi_histo_vld == 1'b1) begin gray_sum <= gray_sum + pi_histo_data; end else begin gray_sum <= 'd0; end end //----------------wr_ram_data------------------ assign wr_ram_data = gray_sum; //----------------wr_ram_en------------------ always @(posedge clk) begin if (rst==1'b1) begin wr_ram_en <= 1'b0; end else begin wr_ram_en <= pi_histo_vld; end end //----------------wr_ram_addr------------------ always @(posedge clk) begin if (rst==1'b1) begin wr_ram_addr <= 'd0; end else if (wr_ram_en == 1'b1) begin wr_ram_addr <= wr_ram_addr + 1'b1; end else begin wr_ram_addr <= 'd0; end end //========================================== //找寻最大最小值 //========================================== //----------------gray_indx------------------ always @(posedge clk) begin if (rst==1'b1) begin gray_idx <= 'd0; end else if (pi_histo_vld == 1'b1) begin gray_idx <= gray_idx + 1'b1; end else begin gray_idx <= 'd0; end end //----------------gray_max------------------ always @(posedge clk) begin if (rst==1'b1) begin gray_max <= 'd0; gray_min <= 'd255; end //检测到一帧图像结束 else if (end_cnt_row == 1'b1) begin gray_max <= 'd0; gray_min <= 'd255; end else if (pi_histo_data != 0 && pi_histo_vld == 1'b1 ) begin if (gray_max <= gray_idx) begin gray_max <= gray_idx; end if (gray_min >= gray_idx) begin gray_min <= gray_idx; end end end //----------------pi_data_dd, data_vld_dd------------------ always @(posedge clk) begin if (rst==1'b1) begin pi_data_dd <= 'd0; data_vld_dd <= 'd0; end else begin pi_data_dd <= pi_data; data_vld_dd <= pi_data_vld; end end //----------------stream_vld_dd------------------ always @(posedge clk) begin if (rst==1'b1) begin stream_vld_dd <= 'd0; end else begin stream_vld_dd <= {stream_vld_dd[1:0], data_vld_dd}; end end assign 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) begin if (rst == 1'b1) begin cnt_col <= 'd0; end else if (add_cnt_col) begin if(end_cnt_col) cnt_col <= 'd0; else cnt_col <= cnt_col + 1'b1; end else begin cnt_col <= 'd0; end end assign add_cnt_col = div_tvalid == 1'b1; assign end_cnt_col = add_cnt_col && cnt_col == IMG_WIDTH - 1; //----------------cnt_row------------------ always @(posedge clk) begin if (rst == 1'b1) begin cnt_row <= 'd0; end else if (add_cnt_row) begin if(end_cnt_row) cnt_row <= 'd0; else cnt_row <= cnt_row + 1'b1; end end assign 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个时钟周期的latency always @(posedge clk) begin if (rst==1'b1) begin pi_hsync_dd <= 'd0; pi_vsync_dd <= 'd0; pi_de_dd <= 'd0; data_dd <= 'd0; end else begin pi_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}; end end assign 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图像处理基础----直方图均衡化啥是直方图均衡化基于FPGA的直方图均衡化具体实现过程2. 进行乘法计算3. 进行除法计算代码设计测试结果的全部内容,更多相关FPGA图像处理基础----直方图均衡化啥是直方图均衡化基于FPGA的直方图均衡化具体实现过程2.内容请搜索靠谱客的其他文章。
发表评论 取消回复