当前位置:   article > 正文

基于FPGA的数字图像处理- 图像分割【5.0】_fpga 图像 阈值分割

fpga 图像 阈值分割
10.5.2 滞后阈值分割电路设计

        滞后阈值需要两个阈值:正如前面所提到的,可以根据所要提取 的图片,提前定好这两个阈值;另外一种方式是采用自动阈值法,一 种典型的阈值求取方法是全局阈值,例如本章所提到的大津法。我们 在这里直接采用第一种方法。 首先需要对上一步骤的极大值抑制后的结果NMS进行缓存,这是由 于需要在其邻域内查找是否有潜在的极大值点,来连接间断的非极大 值点。 很明显,要对之前计算的Sobel模值再次进行缓存,这是由于需要 与NMS结果进行对齐。 还要有一块专门的电路来对Sobel模值的3×3邻域进行查找,是否 有任意一个或多个大于阈值的点,并将查找结果寄存。 设计电路如图10-28所示。

10.5.3 Verilog代码设计

模块需要两个阈值作为输入参数,模块定义如下:
 

  1. module canny(
  2. rst_n,
  3. clk,
  4. din_valid,
  5. din,
  6. dout,
  7. vsync,
  8. vsync_out,
  9. dout_valid
  10. );
  11. parameter DW = 14; //
  12. parameter KSZ = 3; //must be 3
  13. parameter IH = 512;
  14. parameter IW = 640;
  15. parameter ThrHigh = 20; //高阈值
  16. parameter ThrLow = 10; //低阈值
  17. parameter DW_OUT = 20;
  18. parameter DW_IN = 16;
  19. 关键代码如下:
  20. input rst_n;
  21. input clk;
  22. input din_valid;
  23. input [DW-1:0]din;
  24. output [DW-1:0]dout;input vsync;
  25. output vsync_out;
  26. output dout_valid;
  27. wire [DW_OUT-1:0]soble_angle;
  28. wire [DW_OUT-1:0]sobel_mudule;
  29. wire [DW_OUT-1:0]sobel_x;
  30. wire [DW_OUT-1:0]sobel_y;
  31. wire [DW-1:0]sobel_data;
  32. wire sobel_valid;
  33. wire sobel_vsync;
  34. //首先进行高斯滤波和Sobel求边缘
  35. gauss_sobel #(DW,KSZ,IH,IW)
  36. gauss_sobel_ins(
  37. .rst_n (rst_n),
  38. .clk (clk),
  39. .din_valid (din_valid),
  40. .din (din),
  41. .dout(sobel_data), //模值输出
  42. .dout_x (sobel_x), //x方向结果
  43. .dout_y (sobel_y), //y方向结果
  44. .vsync(vsync),
  45. .vsync_out(sobel_vsync),
  46. .dout_valid (sobel_valid)
  47. );
  48. //计算Sobel两个方向绝对值和象限信息
  49. wire [DW_OUT-1:0]sobel_abs_min;
  50. wire [DW_OUT-1:0]sobel_abs_max;wire sobel_abs_valid;
  51. wire [2:0]sobel_abs_info;
  52. //cal the abs of the sobel result(in both x and y
  53. direction)
  54. cordic_pre abs_ins(
  55. .clk(clk),
  56. .rst_n(rst_n),
  57. .din_valid(sobel_valid),
  58. .din_x(sobel_x),
  59. .din_y(sobel_y),
  60. .dout_x(sobel_abs_max),
  61. .dout_y(sobel_abs_min),
  62. .dout_valid(sobel_abs_valid),
  63. .dout_info(sobel_abs_info)
  64. );
  65. defparam abs_ins.DW = DW_OUT;
  66. //缓存中间结果,完成时序匹配
  67. integer i;
  68. integer j;
  69. always @(posedge clk)
  70. begin
  71. sobel_valid_r[0]<= #1 sobel_valid;
  72. sobel_data_r[0] <= #1 sobel_data;
  73. sobel_x_r[0] <= #1 sobel_x;
  74. sobel_y_r[0] <= #1 sobel_y;
  75. for(i=1;i<=NMS_LATENCY;i=i+1)
  76. beginsobel_valid_r[i]<= #1 sobel_valid_r[i-1];
  77. sobel_data_r[i] <= #1 sobel_data_r[i-1];
  78. sobel_x_r[i] <= #1 sobel_x_r[i-1];
  79. sobel_y_r[i] <= #1 sobel_y_r[i-1];
  80. end
  81. end
  82. //将Sobel模值,x方向模值,y方向模值,象限信息结果缓存(开
  83. 窗)
  84. wire [2*DW_OUT+2+DW-1:0]win_buf_din;
  85. assign win_buf_din=
  86. {sobel_abs_max,sobel_abs_min[DW_OUT-
  87. 2:0],sobel_abs_info,sobel_da
  88. ta_r[1]};
  89. wire [KSZ*KSZ*(2*DW_OUT+2+DW)-1:0]win_data_temp;
  90. wire win_valid;
  91. wire win_vsync;
  92. wire [2*DW_OUT+2+DW-1:0]win_org;
  93. wire win_is_boarder;
  94. win_buf #(2*DW_OUT+2+DW,KSZ,IH,IW)
  95. buf_sobel(
  96. .rst_n(rst_n),
  97. .clk(clk),
  98. .din_valid(sobel_valid_r[1]),
  99. .din(win_buf_din),
  100. .dout(win_data_temp),
  101. .dout_org(win_org),
  102. .vsync(sobel_vsync),.vsync_out(win_vsync),
  103. .is_boarder(win_is_boarder),
  104. .dout_valid(win_valid)
  105. );
  106. //缓存结果解析
  107. generate
  108. begin : xhdl1
  109. genvar i;
  110. for (i = 1; i <= KSZ*KSZ; i = i + 1)
  111. begin : xhdl9
  112. assign win_data[i-1]= (win_valid==1'b1)?
  113. win_data_temp[(2*DW_
  114. OUT+2+DW)*i-1 -:2*DW_OUT+2+DW]:
  115. {2*DW_OUT+2+DW{1'b0}};
  116. //得到较大值
  117. assign win_max[i-1] =win_data[i-1][2*DW_OUT+2+DW-
  118. 1-:DW_OUT];
  119. //得到较小值
  120. assign win_min[i-1] =win_data[i-1][DW_OUT+2+DW-
  121. 1-:DW_OUT-1];
  122. //得到象限值
  123. assign win_info[i-1]= win_data[i-1][2+DW -:3];
  124. //得到模值
  125. assign win_r[i-1] = win_data[i-1][DW-1 -:DW];
  126. end
  127. end
  128. endgenerate//buffer mudule value for future use
  129. reg [DW-1:0]mudule_reg[NMS_LATENCY:0];
  130. always @(posedge clk)
  131. begin
  132. mudule_reg[0] <= #1 win_r[med_idx];
  133. for(j=1;j<=NMS_LATENCY;j=j+1)
  134. mudule_reg[j] <= #1 mudule_reg[j-1];
  135. end
  136. //buffer valid for future use
  137. reg [NMS_LATENCY:0]win_valid_r;
  138. always @(posedge clk)
  139. begin
  140. win_valid_r <= #1 {win_valid_r[NMS_LATENCY-
  141. 1:0],win_valid};
  142. end
  143. //根据象限值计算乘法系数索引值
  144. reg [3:0]add_index[3:0];
  145. always @(posedge clk)
  146. begin
  147. if(win_valid==1'b1)
  148. begin
  149. if( (win_info[med_idx]==3'b000) |
  150. (win_info[med_idx]==
  151. 3'b110) )
  152. begin
  153. add_index[0]<= #1 4'd2;
  154. add_index[1]<= #1 4'd5;add_index[2]<= #1 4'd6;
  155. add_index[3]<= #1 4'd3;
  156. end
  157. else if((win_info[med_idx]==3'b001)|
  158. (win_info[med_idx]==3'b111))
  159. begin
  160. add_index[0]<= #1 4'd2;
  161. add_index[1]<= #1 4'd1;
  162. add_index[2]<= #1 4'd6;
  163. add_index[3]<= #1 4'd7;
  164. end
  165. else if((win_info[med_idx]==3'b011)|
  166. (win_info[med_idx]==3'b101))
  167. begin
  168. add_index[0]<= #1 4'd0;
  169. add_index[1]<= #1 4'd1;
  170. add_index[2]<= #1 4'd8;
  171. add_index[3]<= #1 4'd7;
  172. end
  173. else
  174. begin
  175. add_index[0]<= #1 4'd0;
  176. add_index[1]<= #1 4'd3;
  177. add_index[2]<= #1 4'd8;
  178. add_index[3]<= #1 4'd5;
  179. end
  180. end//根据极大值公式进行插值计算 ,计算开销3个时钟
  181. reg [7:0]nms_result;
  182. reg [2*DW_OUT-1:0]nms_max_a4;
  183. reg [2*DW_OUT-1:0]nms_max_a4_r;
  184. reg [2*DW_OUT-1:0]nms_add1;
  185. reg [2*DW_OUT-1:0]nms_add2;
  186. reg [2*DW_OUT-1:0]nms_add3;
  187. reg [2*DW_OUT-1:0]nms_add4;
  188. reg [2*DW_OUT:0]nms_add5;
  189. reg [2*DW_OUT:0]nms_add6;
  190. always @(posedge clk)
  191. begin
  192. if(win_valid_r[0]==1'b1)
  193. begin
  194. nms_max_a4 <= #1 win_r[med_idx]*win_max[med_idx];
  195. nms_add1 <= #1
  196. win_r[add_index[0]]*win_min[med_idx];
  197. nms_add2 <= #1 win_r[add_index[1]]*
  198. (win_max[med_idx]-win_min
  199. [med_idx]);
  200. nms_add3 <= #1
  201. win_r[add_index[2]]*win_min[med_idx];
  202. nms_add4 <= #1 win_r[add_index[3]]*
  203. (win_max[med_idx]-win_min
  204. [med_idx]);
  205. end
  206. if(win_valid_r[1]==1'b1)begin
  207. nms_max_a4_r <= #1 nms_max_a4;
  208. nms_add5 <= #1 nms_add1 + nms_add2;
  209. nms_add6 <= #1 nms_add3 + nms_add4;
  210. end
  211. if(win_valid_r[2]==1'b1)
  212. begin
  213. if(nms_max_a4_r == {2*DW_OUT{1'b0}})
  214. nms_result <= 8'd0;
  215. else if( (nms_max_a4_r >= nms_add5) &&
  216. (nms_max_a4_r >=nms_add6))
  217. nms_result <= 8'd128;
  218. else
  219. nms_result <= 8'd0;
  220. end
  221. end
  222. //缓存极大值结果,用来与模值结果对齐
  223. wire nms_valid;
  224. wire nms_vsync;
  225. wire nms_is_boarder;
  226. wire [7:0]nms_data;
  227. wire [KSZ*KSZ*8-1:0]nms_data_temp;
  228. win_buf #(8,KSZ,IH,IW)
  229. buf_nms(
  230. .rst_n(rst_n),
  231. .clk(clk),
  232. .din_valid(win_valid_r[3]),.din(nms_result),
  233. .dout(nms_data_temp),
  234. .dout_org(nms_data),
  235. .vsync(vsync),
  236. .vsync_out(nms_vsync),
  237. .is_boarder(nms_is_boarder),
  238. .dout_valid(nms_valid)
  239. );
  240. //缓存模值结果,来获得其3*3邻域
  241. wire [KSZ*KSZ*DW-1:0]mudule_temp;
  242. wire [DW-1:0]mudule_org;
  243. wire mudule_valid;
  244. wire mudule_vsync;
  245. wire mudule_is_boarder;
  246. win_buf #(DW,KSZ,IH,IW)
  247. mudule_buf(
  248. .rst_n(rst_n),
  249. .clk(clk),
  250. .din_valid(win_valid_r[3]),
  251. .din(mudule_reg[3]),
  252. .dout(mudule_temp),
  253. .dout_org(mudule_org),
  254. .vsync(vsync),
  255. .vsync_out(mudule_vsync),
  256. .is_boarder(mudule_is_boarder),
  257. .dout_valid(mudule_valid)
  258. );//邻域查找电路 在当前模值的邻域内查找是否有大于高阈值的邻
  259. 域点,如果有,则将结果
  260. //置1,需要两个时钟计算开销
  261. wire mudule_result_temp[0:7];
  262. assign mudule_result_temp[0]= (mudule_data[0]>= ThrHigh)?
  263. 1'b1:1'b0;
  264. assign mudule_result_temp[1]= (mudule_data[1]>= ThrHigh)?
  265. 1'b1:1'b0;
  266. assign mudule_result_temp[2]= (mudule_data[2]>= ThrHigh)?
  267. 1'b1:1'b0;
  268. assign mudule_result_temp[3]= (mudule_data[3]>= ThrHigh)?
  269. 1'b1:1'b0;
  270. assign mudule_result_temp[4]= (mudule_data[5]>= ThrHigh)?
  271. 1'b1:1'b0;
  272. assign mudule_result_temp[5]= (mudule_data[6]>= ThrHigh)?
  273. 1'b1:1'b0;
  274. assign mudule_result_temp[6]= (mudule_data[7]>= ThrHigh)?
  275. 1'b1:1'b0;
  276. assign mudule_result_temp[7]= (mudule_data[8]>= ThrHigh)?
  277. 1'b1:1'b0;
  278. wire mudule_result;
  279. reg mudule_result_tmp[0:6];
  280. always @(posedge clk)
  281. begin
  282. if(nms_valid==1'b1)
  283. beginmudule_result_tmp[0] <= #1 mudule_result_temp[0]
  284. |mudule_result_temp[1];
  285. mudule_result_tmp[1] <= #1 mudule_result_temp[2]
  286. |mudule_result_temp[3];
  287. mudule_result_tmp[2] <= #1 mudule_result_temp[4]
  288. |mudule_result_temp[5];
  289. mudule_result_tmp[3] <= #1 mudule_result_temp[6]
  290. |mudule_result_temp[7];
  291. end
  292. if(nms_valid_r[0]==1'b1)
  293. begin
  294. mudule_result_tmp[4]<=#1
  295. mudule_result_tmp[0]|mudule_result_tmp[1];
  296. mudule_result_tmp[5] <= #1 mudule_result_tmp[2]
  297. |mudule_result_tmp[3];
  298. end
  299. if(nms_valid_r[1]==1'b1)
  300. begin
  301. mudule_result_tmp[6]<=#1
  302. mudule_result_tmp[4]|mudule_result_tmp[5];
  303. end
  304. end
  305. assign mudule_result = mudule_result_tmp[6];
  306. //最后结果计算:大于高阈值直接置1,小于低阈值直接置0。
  307. 在两者之间,若查找到其邻域内有高于高阈值的点,则置1,否则置
  308. 零。
  309. reg [DW-1:0]dout_temp;reg [DW-1:0]mudule_org_r;
  310. reg [DW-1:0]mudule_org_r2;
  311. reg [8-1:0]nms_data_r;
  312. reg [8-1:0]nms_data_r2;
  313. always @(posedge clk)
  314. begin
  315. nms_data_r <= #1 nms_data;
  316. nms_data_r2 <= #1 nms_data_r;
  317. mudule_org_r <= #1 mudule_org;
  318. mudule_org_r2 <= #1 mudule_org_r;
  319. end
  320. always @(posedge clk)
  321. begin
  322. if(nms_valid_r[1]==1'b1)
  323. begin
  324. if(nms_data_r2==8'd128)
  325. begin
  326. if(mudule_org_r2 >= ThrHigh)
  327. dout_temp <= {{DW-8{1'b0}},8'd128};
  328. else if(mudule_org_r2 <= ThrLow)
  329. dout_temp <= {DW{1'b0}};
  330. else
  331. begin
  332. if(mudule_result == 1'b1)
  333. dout_temp <= {{DW-8{1'b0}},8'd128};
  334. else
  335. dout_temp <= {DW{1'b0}};end
  336. end
  337. else
  338. dout_temp <= {DW{1'b0}};
  339. end
  340. end
10.5.4 仿真调试结果

        本模块的大部分模块已经在前面的章节中仿真过了,因此,在这 里我们只列出二维图像的仿真结果。图10-29(b)图像是对图10- 29(a)图像进行高阈值为20、低阈值为10的Canny算子运算后的结 果。

由图10-29可以看出,我们的设计达到了预期的目的。

第11章 视频接口

11.1 视频输入接口

11.1.1 模拟视频输入

1.模拟视频简介 模拟视频是指由连续的模拟信号组成的视频图像。模拟信号的波 形模拟着信息的变化,其特点是幅度连续(连续的含义是在某一取值 范围内可以取无限多个数值)。 摄像机是获取视频信号的来源,早期的摄像机以电子管作为光电 转换器件,把外界的光信号转换为电信号。摄像机前的被拍摄物体的 不同亮度对应于不同的亮度值,摄像机电子管中的电流会发生相应的 变化。模拟信号就是利用这种电流的变化来表示或者模拟所拍摄的图 像,记录下它们的光学特征;然后通过调制和解调,将信号传输给接 收机;通过电子枪显示在荧光屏上,还原成原来的光学图像。这也是 电视广播的基本原理和过程。 模拟视频信号技术成熟,价格低,系统可靠性高,但是不宜进行 长期存放,不适宜进行多次复制。随着时间的推移,录像带上的图像 信号强度会逐渐衰减,造成图像质量下降、色彩失真等现象。 2.模拟视频分类模拟视频信号主要包括亮度信号、色度信号、复合同步信号和伴 音信号。为了实现模拟视频在不同环境下的传输和连接,通常提供以 下几种信号类型。

1)复合视频信号 复合视频信号(Composite Video Signal,即我们常说的AV端 子)是指包含亮度信号、色差信号和所有定时信号的单一模拟信号, 其接口外形如图11-1所示。这种类型的视频信号不包含伴音信号,带 宽较窄,一般只能提供240线左右的水平分辨率。大多数视频卡都提供 这种类型的视频接口,如图11-1所示。

2)分量视频信号 分量视频信号(Component Video Signal)是指每个基色分量作 为独守的电视信号。每个基色既可以分别用R、G、B表示,也可以用亮 度-色差表示,如Y、I、Q或Y、U、V等。使用分量视频信号是表示颜色 的最好方法,但需要比较宽的带宽和同步信号。计算机输出的VGA视频 信号即为分量形式的视频信号,其接口外形如图11-2所示。

3)分离视频信号 分离视频信号S-Video(Separated Video)是分量视频信号和复 合视频信号的一种折中方案,它将亮度Y和色差信号C分离,既减少了 亮度信号和色差信号之间的交叉干扰,又可提高亮度信号的带宽,其 具体接口外形如图11-3所示。大多数视频卡均提供这种类型的视频接 口。

4)射频信号 为了实现模拟视频信号的远距离传输,必须把包括亮度信号、色 度信号、复合同步信号和伴音信号在内的全电视信号调制成射频信 号,每个信号占用一个频道。当视频接收设备(如电视机)接收到射 频信号时,先从射频信号中解调出全电视信号,再还原成图像和声音 信号。射频信号的接口外形如图11-4所示,一般在TV卡上提供这种接 口。

为了便于模拟视频的处理、传输和存储,形成了相关的模拟视频 国际标准——广播视频标准,用来规范和统一模拟视频体系。 3.模拟视频格式 模拟视频信号主要有3种格式:PAL、NTSC和SECAM。 1)PAL制式 PAL 制 式 是 电 视 广 播 中 色 彩 编 码 的 一 种 方 法 , 全 名 为 Phase Alternating Line(逐行倒相)。除北美、东亚部分地区使用NTSC制 式,以及中东地区、法国及东欧地区采用SECAM制式以外,世界上大部 分国家和地区都采用PAL制式。PAL由德国人Walter Bruch在1967年提 出,当时他为Teleftmken工作。“PAL”被用来指扫描线为625线、帧 频为每秒25fps、隔行扫描、PAL色彩编码的电视制式。2)NTSC制式 NTSC制式又简称N制,是1952年12月由美国国家电视标准委员会 (National Television System Committee,NTSC)制定的彩色电视 广播标准。它属于同时制,帧频为每秒30fps,扫描线为525,逐行扫 描,画面比例为4∶3。这种制式的色度信号调制包括了平衡调制和正 交调制两种,解决了彩色黑白电视广播的兼容问题,但存在相位容易 失真、色彩不太稳定的缺点。美国、加拿大、墨西哥等大部分美洲国 家,以及中国台湾地区、日本、韩国、菲律宾等均采用这种制式。中 国香港地区部分电视公司也采用NTSC制式广播。

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

闽ICP备14008679号