当前位置:   article > 正文

基于FPGA的数字图像处理-直方图操作【3.3】_fpga图像处理

fpga图像处理
6.5.2 FPGA直方图均衡化

首先再次列出直方图均衡化的公式:


上式中,H(i)为第i级灰度的像素个数,A0 为图像的面积,也即像素总数。因此,计算均衡后的图像步骤如下:
(1)首先计算出当前图像的直方图H(i)。

        在实际应用中,处理帧缓存是费时费力费资源的一件事情,在许 多情况下,图像的变换比较慢,在这种情况下的一个近似是当建立当 前帧的直方图统计结果时使用从前一帧得到的映射。结果是直方图均 衡化可能不是非常准确,但是消耗的资源和处理的延时都有显著地减 少,如图6-27所示。

        图6-27 近似的直方图均衡化 第一步的直方图计算我们已经在前面介绍过了,接下来详细介绍 后面的几个计算步骤。 1.直方图累计和 根据数学定义,直方图累加和的定义是小于指定像素的所有像素 的统计值之和。因此,这个阶段放在直方图统计值读出阶段来进行累 加是再合适不过了。 在直方图统计代码里面添加如下代码:

  1. reg [TW-1:0]hist_cnt; //直方图统计累加和寄存器
  2. always @(posedge clk or negedge rst_n)
  3. if ((~(rst_n)) == 1'b1)
  4. hist_cnt <= {TW{1'b0}}; //复位清零
  5. else
  6. if (vsync_r == 1'b0 & vsync == 1'b1) //新的一帧到来时清
  7. hist_cnt <= {TW{1'b0}};
  8. else
  9. if (out_pixel[0]== 1'b1) //每个像素读出时刻
  10. hist_cnt <= hist_cnt + q_b; //将结果累加

        仅仅得到累加和是不够的,因为需要对累加和进行随机地址访 问,而不是顺序读出。这个时候就需要将累加和缓存。同样地,采用 一个双口RAM对累加和结果进行缓存,同时完成时序对齐。 需要在之前的直方图统计模块加入两个接口,一个是统计和的地 址输入,负责选通对累计和进行寻址,一个是数据输出,如下所示:

  1. module histogram_2d(
  2. rst_n,clk,
  3. din_valid,
  4. din,
  5. dout,
  6. vsync,
  7. dout_valid,
  8. rdyOutput,
  9. 'ifdef Equalize
  10. hist_cnt_addr,
  11. hist_cnt_out,
  12. 'endif
  13. int_flag
  14. );
  15. 'ifdef Equalize
  16. input [DW-1:0]hist_cnt_addr;
  17. output reg [TW-1:0]hist_cnt_out;
  18. 'endif
  19. 代码如下:
  20. reg [DW:0]out_pixel_r;
  21. reg [DW-1:0]out_pixel_r2;
  22. wire [TW-1:0]hist_cnt_temp;
  23. always @(posedge clk or negedge rst_n)
  24. if ((~(rst_n)) == 1'b1)
  25. begin
  26. out_pixel_r <= {DW+1{1'b0}};
  27. out_pixel_r2 <= {DW{1'b0}};
  28. hist_cnt_out <= {TW{1'b0}};end
  29. else
  30. begin
  31. out_pixel_r <= #1 out_pixel;
  32. out_pixel_r2 <= #1 out_pixel_r[DW:1];
  33. hist_cnt_out <= #1 hist_cnt_temp; //将数据打一拍后输出
  34. end
  35. hist_buffer hist_cnt_buf(
  36. .address_a(out_pixel_r2), //写入地址,直方图当前地址
  37. .address_b(hist_cnt_addr), //读出地址
  38. .clock(clk), //同步时钟
  39. .data_a(hist_cnt), //写入数据
  40. .data_b(),
  41. .wren_a(dout_valid), //写入时刻:直方图数据有效
  42. .wren_b(1'b0),
  43. .q_a(),
  44. .q_b(hist_cnt_temp) //输出数据
  45. );
  46. defparam hist_cnt_buf.AW = DW;
  47. defparam hist_cnt_buf.DW = TW;

累加和的计算情况如图6-28所示。

可见,累加和很好地完成了累加工作。不妨输入前几个累积和地址对累加和进行读出,如图6-29所示。

        由此可见,数据输出正确。由于我们将输出打了一个节拍输出, 因 此 输 出 会 延 迟 一 个 时 钟 。 注 意 , 到 此 时 由 于 已 经 统 计 完 毕 , hist_cnt刚好为图像的像素总数327680,即640×512。 2.归一化计算 将第3步和第4步放在一起进行计算,由于这个过程也是把像素归 一化到0~255的过程,因此我们也将此成为归一化计算。 归一化计算的步骤是先乘以灰度最大值,然后再除以像素总数: 图像宽度×图像高度。 通常情况下不会直接调用乘法器和除法器对上式进行计算,这样 做是不合适的。对于固定的位宽和图像分辨率来说,这个计算过程是 可定量的,也就是这个归一化系数是已知的。而往往在应用过程中, 大部分场合有效的数据位宽和分辨率的组合也不会太多。 本 书 以 图 像 位 宽 为 8 位 , 图 像 分 辨 率 为 640×512 和 分 辨 率 为 512×512位例来进行说明。首先我们设定这个归一化系数为N。 对于第一种情况,有

其他的分辨率及位宽也可以通过类似的方法进行转换。接下来我们将会详细给出其Verilog实例代码设计。

  1. 3.Verilog代码设计
  2. 模块定义如下:
  3. module hist_equalized(
  4. rst_n,
  5. clk,
  6. din_valid, //输入数据有效din, //输入数据
  7. dout, //输出数据
  8. vsync, //输入场同步
  9. dout_valid, //输出有效
  10. vsync_out //输出场同步
  11. );
  12. parameter DW = 8; //数据位宽
  13. parameter IH = 512; //图像高度
  14. parameter IW = 640; //图像宽度
  15. parameter TW = 32; //直方图数据位宽
  16. localparam TOTAL_CNT = IW * IH;
  17. localparam HALF_WIDTH = (TW>>1);
  18. //计算开销
  19. localparam latency = 6;
  20. input rst_n;
  21. input clk;
  22. input din_valid;
  23. input [DW-1:0]din;
  24. output [DW-1:0]dout;
  25. input vsync;
  26. output vsync_out;
  27. output dout_valid;
  28. reg [DW-1:0]hist_cnt_addr;
  29. wire [TW-1:0]hist_cnt_out;
  30. //首先需例化一个直方图统计模块对输入图像进行直方图统计,
  31. //注意我们只需得到直方图统计累加和信息
  32. histogram_2d hist(.rst_n(rst_n),
  33. .clk(clk),
  34. .din_valid(din_valid),
  35. .din(din),
  36. .vsync(vsync),
  37. .hist_cnt_addr(hist_cnt_addr), //累积和输入地址
  38. .hist_cnt_out(hist_cnt_out) //累加和输出
  39. );
  40. defparam hist.DW = DW;
  41. defparam hist.IH = IH;
  42. defparam hist.IW = IW;
  43. wire vsync_fall;
  44. wire valid;
  45. reg [1:0]frame_cnt;
  46. reg hist_valid_temp;
  47. reg vsync_r;
  48. //由于至少需要等到第一帧输出完毕之后才能完成第一帧数据的
  49. 直方图统计信息,
  50. //因此有必要先对图像帧进行计数
  51. always @(posedge clk or negedge rst_n)
  52. if (((~(rst_n))) == 1'b1)
  53. begin
  54. vsync_r <= #1 1'b0;
  55. hist_valid_temp <= 1'b0;
  56. frame_cnt <= 2'b00;
  57. end
  58. elsebegin
  59. vsync_r <= #1 vsync;
  60. if(vsync_fall)
  61. frame_cnt <= frame_cnt + 2'b01;//每帧结束时帧
  62. 计数加1
  63. else
  64. frame_cnt <= frame_cnt;
  65. if(frame_cnt >= 2'b10) //第二行开始输入均衡操作才开始有
  66. hist_valid_temp <= 1'b1;
  67. end
  68. //场同步下降沿信号
  69. assign vsync_fall = (vsync & ~vsync_r);
  70. //全局有效信号
  71. assign valid = hist_valid_temp & din_valid;
  72. //缓存全局有效信号,完成时序对齐
  73. reg [latency:0]valid_r;
  74. always @(posedge clk or negedge rst_n)
  75. if (((~(rst_n))) == 1'b1)
  76. begin
  77. valid_r[latency:0]<= {latency+1{1'b0}};
  78. end
  79. else
  80. begin
  81. valid_r <= #1 {valid_r[latency-1:0],valid};
  82. end
  83. reg [DW-1:0]din_r;//缓存输入数据完成时序对齐
  84. always @(posedge clk or negedge rst_n)
  85. if (((~(rst_n))) == 1'b1)
  86. begin
  87. din_r <= {DW{1'b0}};
  88. end
  89. else
  90. begin
  91. din_r <= #1 din;
  92. end
  93. //查询当前像素的直方图统计累加和
  94. always @(posedge clk or negedge rst_n)
  95. if (((~(rst_n))) == 1'b1)
  96. begin
  97. hist_cnt_addr <= {DW{1'b0}};
  98. end
  99. else
  100. begin
  101. if(valid_r[0])
  102. hist_cnt_addr <= #1 din_r;
  103. end
  104. reg [2*TW-1:0]mul_temp[0:2];
  105. reg [DW-1:0]dout_temp;
  106. //对于分辨率为512*512的图像而言
  107. generate
  108. if((IW ==512) & (IH ==512) )begin :IW_512
  109. always @(posedge clk or negedge rst_n)if (((~(rst_n))) == 1'b1)
  110. begin
  111. mul_temp[0]<= {2*TW{1'b0}};
  112. end
  113. else
  114. begin
  115. if(valid_r[1])
  116. //hist_cnt_out*255,
  117. mul_temp[0] <= #1 {{TWDW{1'b0}},hist_cnt_out[TW-1:0],
  118. {DW{1'b0}}} -{{TW{1'b0}},hist_cnt_out};
  119. if(valid_r[1])
  120. //hist_cnt_out/(512*512) IW = IH = 512
  121. mul_temp[1]<= #1 {{18{1'b0}},mul_temp[0][2*TW-
  122. 1:18]};
  123. if(valid_r[2])
  124. dout_temp <= #1 mul_temp[1][DW-1:0];
  125. end
  126. end
  127. endgenerate
  128. //对于分辨率为640*512的图像而言
  129. generate
  130. if(IW ==640 & IH ==512 )begin :IW_640
  131. wire [2*TW-1:0]dout_tmp ;
  132. assign dout_tmp = {{16{1'b0}},mul_temp[2][2*TW-1:16]};
  133. always @(posedge clk or negedge rst_n)
  134. if (((~(rst_n))) == 1'b1)begin
  135. mul_temp[0]<= {2*TW{1'b0}};
  136. end
  137. else
  138. begin
  139. if(valid_r[1])
  140. //hist_cnt_out*51,DW must be 8
  141. //hist_cnt_out*32 + hist_cnt_out*16
  142. mul_temp[0]<=#1{{TW-5{1'b0}},hist_cnt_out[TW-
  143. 1:0],{5{1'b0}}}
  144. + {{TW-4{1'b0}},hist_cnt_out[TW-1:0],{4{1'b0}}};
  145. //hist_cnt_out*2 + hist_cnt_out*1
  146. mul_temp[1]<= #1 {{TW{1'b0}},hist_cnt_out[TW-
  147. 1:0]} +
  148. {{TW-1{1'b0}},hist_cnt_out[TW-1:0],{1{1'b0}}};
  149. if(valid_r[1])
  150. //hist_cnt_out/(64*2*512)
  151. mul_temp[2]<= #1 mul_temp[0]+ mul_temp[1];
  152. //
  153. if(valid_r[2])
  154. dout_temp <= #1 dout_tmp[DW-1:0];
  155. end
  156. end
  157. endgenerate
  158. //完成数据输出与对齐
  159. assign dout = dout_temp;
  160. assign dout_valid = valid_r[latency];assign vsync_out = vsync;
  161. endmodule
  162. 4.仿真结果
  163. Testbench设计如下:
  164. /*hist equalized operation module*/
  165. generate
  166. if(hist_equalized_en != 0)begin :equalized_operation
  167. wire equalized_dvalid;
  168. wire [local_dw - 1:0]equalized_data;
  169. wire equalized_vsync;
  170. wire equalized_dvalid_in;
  171. wire [local_dw - 1:0]equalized_data_in;
  172. wire equalized_vsync_in;
  173. integer fp_equalized,cnt_equalized=0;
  174. hist_equalized #(8,ih,iw,hist_dw)
  175. equalized_ins(
  176. .rst_n (reset_l),
  177. .clk (cap_clk),
  178. .din (equalized_data_in[7:0]),
  179. .din_valid (equalized_dvalid_in),
  180. .dout_valid (equalized_dvalid),
  181. .vsync(equalized_vsync_in),
  182. .vsync_out(equalized_vsync),
  183. .dout (equalized_data[7:0])
  184. );
  185. assign equalized_data_in = cap_data;
  186. assign equalized_vsync_in = cap_vsync;assign equalized_dvalid_in = cap_dvalid;
  187. always @(posedge cap_clk or posedge equalized_vsync )
  188. if (((~(equalized_vsync))) == 1'b0)
  189. cnt_equalized=0;
  190. else
  191. begin
  192. if (equalized_dvalid == 1'b1)
  193. begin
  194. fp_equalized =
  195. $fopen("txt_out/equalized.txt","r+");
  196. $fseek(fp_equalized,cnt_equalized,0);
  197. $fdisplay(fp_equalized,"%04x\n",equalized_data[7:0]
  198. );
  199. $fclose(fp_equalized);
  200. cnt_equalized<=cnt_equalized+6;
  201. end
  202. end
  203. end
  204. endgenerate

通过两张测试图来验证逻辑功能:一幅较暗的图像和一幅较亮的图像,处理结果如图6-30和图6-31所示。

        由测试结果可见,这两幅过曝光和曝光不足的图像,经过均衡化 之后的效果图差别不大,对比度都非常高,设计代码达到了预期的均 衡目的。 对于直方图的规定操作,也可以采用类似直方图均衡的运算方 法,有兴趣的读者可以自己尝试去设计相关逻辑。

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号