当前位置:   article > 正文

基于FPGA的图像处理4--线性滤波-均值滤波_fpga均值滤波

fpga均值滤波

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

图像预处理中,最基础也最重要的处理方法是图像滤波与增强。图像滤波可以很好地消除测量成像或者环境带来的随机噪声,高斯噪声和椒盐噪声等。图像增强可以增强图像细节,提高图像对比度。

滤波器的种类有很多种。按照输出和输入之间是否有唯一且确定的传递函数,我们可以把滤波器分为线性滤波器和非线性滤波器两种。我们介绍线性滤波器中的均值滤波器。

均值滤波器是典型的线性滤波算法,主要方法为邻域平均法,即用一个图像区域的各个像素的平均值来替代原图像的各个像素值。

        均值滤波器的主要作用是减小图像灰度值的“尖锐”变化从而达到减小噪声的目的。但是,由于图像边缘在一般情况下也是由图像灰度尖锐化引起的,因此,均值滤波也存在边缘模糊的问题。

        均值滤波的数学定义为: 

        其中r为处理窗口的半径, 为待求的窗口内像素均值,I(x,y)为输入像素值,g(x,y)为输出像素值。 

图 1 

        图1为均值滤波的电路结构图。该电路主要由四部分组成,第一个部分是用于求和的加法树ADD_Tree,第二个部分是用于产生加法树输出数据是否有效的dvalid标志信号的Tvalid_Counter,第三部分使用来抓取经过累加求和后的有效数据的Data_Capture,第四部分是用求均值的Average_Op。

图 2

        图2所示是均值滤波电路中的加法树ADD_Tree模块的电路结构图。该均值滤波使用3x3大小的核进行滤波。因此,在ADD_Tree模块中,先进行3x3大小的开窗操作,即将行列对齐后的3行数据在寄存器中打3拍,这样在9个寄存器中的值就是3x3滤波核所需要的对应图像数据值了。当滤波窗口数据有效后,9个数据同时进入后续的加法数进行累加操作。这里需要注意的是,我们知道2个8位的数相加,可能会产生一个9位的数,因此,每一级的和比前一级加数的位宽大1,这样能避免和值的溢出。 

图 3 

图 4 

        图3和图4是ADD_Tree模块的仿真图,从仿真结果看,Tvalid_counter模块在开端产生的dvalid信号是可以和ADD_Tree模块产生的累加和add_data值对应上,但是在因为设计中的计数器的关系,Tvalid_counter模块比ADD_Tree模块早一个时钟周期拉低了dvalid信号,但这时ADD_Tree模块产生的add_data信号是有效。因此,我设计了一个Data_Capture电路来对ADD_Tree模块产生的add_data和Tvalid_counter模块产生的dvalid信号,进行采样后重新生成。此时,Tvalid_counter模块锁存来自ADD_Tree模块的有效数据有两种情况,第一种情况是:只要Tvalid_counter模块输出的dvalid信号有效(高电平),则锁存数据输出cap_data,并输出cap_valid为有效(高电平);第二种情况是:当Tvalid_counter模块输出的dvalid信号无效(低电平),且其上一拍dvalid信号有效,也锁存数据输出cap_data,并输出cap_valid为有效(高电平);除了上述两种场景外的其他场景,Tvalid_counter模块不锁存数据,同时将cap_valid置为无效(低电平)。

图 5 

         图5所示为Data_Capture模块电路输出的仿真图,可以看到输出值是正确的求和累加时序。        

图 6

        图6所示为3x3大小的均值滤波的求均值电路结构图。该电路结构的设计思想是这样的:采用的是近似计算的原理。因为是3x3大小的求均值,因此是执行din_data/9的运算。对于这个除法操作可以使用除法电路来做也可以使用移位运算近似获得。这里,我使用的移位运算的近似逼近。因为9不是2的任何次幂,因此无法直接使用移位操作来实现。所以我将din_data/9做了如下转换: 

        依照如上所示的转换公式,便将din_data/9操作转换成了两级移位运算和两级加法运算,其运算结构如图6所示。 

图 7 

        图7所示为Average_Op模块的仿真波形图,可以看到因为是整型定点数移位操作,所以会有精度的丢失。均值滤波具体实现如下所示:

  1. module Average3x3 #(
  2. parameter LINE_NUM = 3,
  3. parameter PIXEL_WIDTH = 14,
  4. parameter KX_WIDTH =3,
  5. parameter IMAGE_WIDTH = 128
  6. )(clk,arstn,data_in,din_valid,data_out,dout_valid);
  7. function integer clogb2(input integer bit_depth);
  8. begin
  9. for(clogb2 = 0;bit_depth >0; clogb2 = clogb2 + 1)
  10. bit_depth = bit_depth >> 1;
  11. end
  12. endfunction
  13. localparam CNT_WIDTH = clogb2(IMAGE_WIDTH-1);
  14. localparam DATA_WIDTH = PIXEL_WIDTH * LINE_NUM;
  15. input clk;
  16. input arstn;
  17. input [DATA_WIDTH-1:0]data_in;
  18. input din_valid;
  19. output [PIXEL_WIDTH+4-1:0]data_out;
  20. output dout_valid;
  21. reg [PIXEL_WIDTH-1:0]k00_reg;
  22. reg [PIXEL_WIDTH-1:0]k01_reg;
  23. reg [PIXEL_WIDTH-1:0]k02_reg;
  24. reg [PIXEL_WIDTH-1:0]k10_reg;
  25. reg [PIXEL_WIDTH-1:0]k11_reg;
  26. reg [PIXEL_WIDTH-1:0]k12_reg;
  27. reg [PIXEL_WIDTH-1:0]k20_reg;
  28. reg [PIXEL_WIDTH-1:0]k21_reg;
  29. reg [PIXEL_WIDTH-1:0]k22_reg;
  30. reg [CNT_WIDTH:0]cnt_reg;
  31. reg [CNT_WIDTH:0]cnt;
  32. always@(posedge clk or negedge arstn)
  33. begin
  34. if(~arstn)
  35. begin
  36. k00_reg <= 0;
  37. k01_reg <= 0;
  38. k02_reg <= 0;
  39. end
  40. else
  41. begin
  42. if(din_valid)
  43. begin
  44. k00_reg <= data_in[PIXEL_WIDTH-1:0];
  45. k01_reg <= data_in[2*PIXEL_WIDTH-1:PIXEL_WIDTH];
  46. k02_reg <= data_in[3*PIXEL_WIDTH-1:2*PIXEL_WIDTH];
  47. end
  48. end
  49. end
  50. always@(posedge clk or negedge arstn)
  51. begin
  52. if(~arstn)
  53. begin
  54. k10_reg <= 0;
  55. k11_reg <= 0;
  56. k12_reg <= 0;
  57. end
  58. else
  59. begin
  60. k10_reg <= k00_reg;
  61. k11_reg <= k01_reg;
  62. k12_reg <= k02_reg;
  63. end
  64. end
  65. always@(posedge clk or negedge arstn)
  66. begin
  67. if(~arstn)
  68. begin
  69. k20_reg <= 0;
  70. k21_reg <= 0;
  71. k22_reg <= 0;
  72. end
  73. else
  74. begin
  75. k20_reg <= k10_reg;
  76. k21_reg <= k11_reg;
  77. k22_reg <= k12_reg;
  78. end
  79. end
  80. /* first add pipe */
  81. reg [PIXEL_WIDTH+1-1:0]add_delay_00;
  82. reg [PIXEL_WIDTH+1-1:0]add_delay_01;
  83. reg [PIXEL_WIDTH+1-1:0]add_delay_02;
  84. reg [PIXEL_WIDTH+1-1:0]add_delay_03;
  85. reg [PIXEL_WIDTH+1-1:0]add_delay_04;
  86. always@(posedge clk or negedge arstn)
  87. begin
  88. if(~arstn)
  89. begin
  90. add_delay_00 <= 0;
  91. add_delay_01 <= 0;
  92. add_delay_02 <= 0;
  93. add_delay_03 <= 0;
  94. add_delay_04 <= 0;
  95. end
  96. else
  97. begin
  98. add_delay_00 <= k00_reg + k01_reg;
  99. add_delay_01 <= k02_reg + k10_reg;
  100. add_delay_02 <= k11_reg + k12_reg;
  101. add_delay_03 <= k20_reg + k21_reg;
  102. add_delay_04 <= k22_reg;
  103. end
  104. end
  105. /* second add pipe */
  106. reg [PIXEL_WIDTH+2-1:0]add_delay_10;
  107. reg [PIXEL_WIDTH+2-1:0]add_delay_11;
  108. reg [PIXEL_WIDTH+2-1:0]add_delay_12;
  109. always@(posedge clk or negedge arstn)
  110. begin
  111. if(~arstn)
  112. begin
  113. add_delay_10 <= 0;
  114. add_delay_11 <= 0;
  115. add_delay_12 <= 0;
  116. end
  117. else
  118. begin
  119. add_delay_10 <= add_delay_00 + add_delay_01;
  120. add_delay_11 <= add_delay_02 + add_delay_03;
  121. add_delay_12 <= add_delay_04;
  122. end
  123. end
  124. /* Third add pipe */
  125. reg [PIXEL_WIDTH+3-1:0]add_delay_20;
  126. reg [PIXEL_WIDTH+3-1:0]add_delay_21;
  127. always@(posedge clk or negedge arstn)
  128. begin
  129. if(~arstn)
  130. begin
  131. add_delay_20 <= 0;
  132. add_delay_21 <= 0;
  133. end
  134. else
  135. begin
  136. add_delay_20 <= add_delay_10 + add_delay_11;
  137. add_delay_21 <= add_delay_12;
  138. end
  139. end
  140. /* Fourth add pipe */
  141. reg [PIXEL_WIDTH+4-1:0]add_delay_30;
  142. always@(posedge clk or negedge arstn)
  143. begin
  144. if(~arstn)
  145. add_delay_30 <= 0;
  146. else
  147. add_delay_30 <= add_delay_20 + add_delay_21;
  148. end
  149. assign data_out = add_delay_30;
  150. always@(posedge clk or negedge arstn)
  151. begin
  152. if(~arstn)
  153. cnt_reg <= 0;
  154. else
  155. cnt_reg <= cnt;
  156. end
  157. always@(*)
  158. begin
  159. if(din_valid)
  160. begin
  161. if(cnt_reg == IMAGE_WIDTH - 1)
  162. cnt = 0;
  163. else
  164. cnt = cnt_reg + 1'b1;
  165. end
  166. else
  167. cnt = cnt_reg;
  168. end
  169. /* dout_valid pipe*/
  170. reg tvalid;
  171. reg tvalid_delay_0;
  172. reg tvalid_delay_1;
  173. reg tvalid_delay_2;
  174. reg tvalid_delay_3;
  175. always@(posedge clk or negedge arstn)
  176. begin
  177. if(~arstn)
  178. tvalid <= 0;
  179. else
  180. begin
  181. if(cnt == KX_WIDTH)
  182. tvalid <= 1'b1;
  183. else if(cnt_reg == IMAGE_WIDTH - 1)
  184. tvalid <= 1'b0;
  185. else
  186. tvalid <= tvalid;
  187. end
  188. end
  189. always@(posedge clk or negedge arstn)
  190. begin
  191. if(~arstn)
  192. begin
  193. tvalid_delay_0 <= 0;
  194. tvalid_delay_1 <= 0;
  195. tvalid_delay_2 <= 0;
  196. tvalid_delay_3 <= 0;
  197. end
  198. else
  199. begin
  200. tvalid_delay_0 <= tvalid;
  201. tvalid_delay_1 <= tvalid_delay_0;
  202. tvalid_delay_2 <= tvalid_delay_1;
  203. tvalid_delay_3 <= tvalid_delay_2;
  204. end
  205. end
  206. assign dout_valid = tvalid_delay_3;
  207. endmodule

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/535114
推荐阅读
相关标签
  

闽ICP备14008679号