赞
踩
滞后阈值需要两个阈值:正如前面所提到的,可以根据所要提取 的图片,提前定好这两个阈值;另外一种方式是采用自动阈值法,一 种典型的阈值求取方法是全局阈值,例如本章所提到的大津法。我们 在这里直接采用第一种方法。 首先需要对上一步骤的极大值抑制后的结果NMS进行缓存,这是由 于需要在其邻域内查找是否有潜在的极大值点,来连接间断的非极大 值点。 很明显,要对之前计算的Sobel模值再次进行缓存,这是由于需要 与NMS结果进行对齐。 还要有一块专门的电路来对Sobel模值的3×3邻域进行查找,是否 有任意一个或多个大于阈值的点,并将查找结果寄存。 设计电路如图10-28所示。
模块需要两个阈值作为输入参数,模块定义如下:
- module canny(
- rst_n,
- clk,
- din_valid,
- din,
- dout,
- vsync,
- vsync_out,
- dout_valid
- );
- parameter DW = 14; //
- parameter KSZ = 3; //must be 3
- parameter IH = 512;
- parameter IW = 640;
- parameter ThrHigh = 20; //高阈值
- parameter ThrLow = 10; //低阈值
- parameter DW_OUT = 20;
- parameter DW_IN = 16;
- 关键代码如下:
- input rst_n;
- input clk;
- input din_valid;
- input [DW-1:0]din;
- output [DW-1:0]dout;input vsync;
- output vsync_out;
- output dout_valid;
- wire [DW_OUT-1:0]soble_angle;
- wire [DW_OUT-1:0]sobel_mudule;
- wire [DW_OUT-1:0]sobel_x;
- wire [DW_OUT-1:0]sobel_y;
- wire [DW-1:0]sobel_data;
- wire sobel_valid;
- wire sobel_vsync;
- //首先进行高斯滤波和Sobel求边缘
- gauss_sobel #(DW,KSZ,IH,IW)
- gauss_sobel_ins(
- .rst_n (rst_n),
- .clk (clk),
- .din_valid (din_valid),
- .din (din),
- .dout(sobel_data), //模值输出
- .dout_x (sobel_x), //x方向结果
- .dout_y (sobel_y), //y方向结果
- .vsync(vsync),
- .vsync_out(sobel_vsync),
- .dout_valid (sobel_valid)
- );
- //计算Sobel两个方向绝对值和象限信息
- wire [DW_OUT-1:0]sobel_abs_min;
- wire [DW_OUT-1:0]sobel_abs_max;wire sobel_abs_valid;
- wire [2:0]sobel_abs_info;
- //cal the abs of the sobel result(in both x and y
- direction)
- cordic_pre abs_ins(
- .clk(clk),
- .rst_n(rst_n),
- .din_valid(sobel_valid),
- .din_x(sobel_x),
- .din_y(sobel_y),
- .dout_x(sobel_abs_max),
- .dout_y(sobel_abs_min),
- .dout_valid(sobel_abs_valid),
- .dout_info(sobel_abs_info)
- );
- defparam abs_ins.DW = DW_OUT;
- //缓存中间结果,完成时序匹配
- integer i;
- integer j;
- always @(posedge clk)
- begin
- sobel_valid_r[0]<= #1 sobel_valid;
- sobel_data_r[0] <= #1 sobel_data;
- sobel_x_r[0] <= #1 sobel_x;
- sobel_y_r[0] <= #1 sobel_y;
- for(i=1;i<=NMS_LATENCY;i=i+1)
- beginsobel_valid_r[i]<= #1 sobel_valid_r[i-1];
- sobel_data_r[i] <= #1 sobel_data_r[i-1];
- sobel_x_r[i] <= #1 sobel_x_r[i-1];
- sobel_y_r[i] <= #1 sobel_y_r[i-1];
- end
- end
- //将Sobel模值,x方向模值,y方向模值,象限信息结果缓存(开
- 窗)
- wire [2*DW_OUT+2+DW-1:0]win_buf_din;
- assign win_buf_din=
- {sobel_abs_max,sobel_abs_min[DW_OUT-
- 2:0],sobel_abs_info,sobel_da
- ta_r[1]};
- wire [KSZ*KSZ*(2*DW_OUT+2+DW)-1:0]win_data_temp;
- wire win_valid;
- wire win_vsync;
- wire [2*DW_OUT+2+DW-1:0]win_org;
- wire win_is_boarder;
- win_buf #(2*DW_OUT+2+DW,KSZ,IH,IW)
- buf_sobel(
- .rst_n(rst_n),
- .clk(clk),
- .din_valid(sobel_valid_r[1]),
- .din(win_buf_din),
- .dout(win_data_temp),
- .dout_org(win_org),
- .vsync(sobel_vsync),.vsync_out(win_vsync),
- .is_boarder(win_is_boarder),
- .dout_valid(win_valid)
- );
- //缓存结果解析
- generate
- begin : xhdl1
- genvar i;
- for (i = 1; i <= KSZ*KSZ; i = i + 1)
- begin : xhdl9
- assign win_data[i-1]= (win_valid==1'b1)?
- win_data_temp[(2*DW_
- OUT+2+DW)*i-1 -:2*DW_OUT+2+DW]:
- {2*DW_OUT+2+DW{1'b0}};
- //得到较大值
- assign win_max[i-1] =win_data[i-1][2*DW_OUT+2+DW-
- 1-:DW_OUT];
- //得到较小值
- assign win_min[i-1] =win_data[i-1][DW_OUT+2+DW-
- 1-:DW_OUT-1];
- //得到象限值
- assign win_info[i-1]= win_data[i-1][2+DW -:3];
- //得到模值
- assign win_r[i-1] = win_data[i-1][DW-1 -:DW];
- end
- end
- endgenerate//buffer mudule value for future use
- reg [DW-1:0]mudule_reg[NMS_LATENCY:0];
- always @(posedge clk)
- begin
- mudule_reg[0] <= #1 win_r[med_idx];
- for(j=1;j<=NMS_LATENCY;j=j+1)
- mudule_reg[j] <= #1 mudule_reg[j-1];
- end
- //buffer valid for future use
- reg [NMS_LATENCY:0]win_valid_r;
- always @(posedge clk)
- begin
- win_valid_r <= #1 {win_valid_r[NMS_LATENCY-
- 1:0],win_valid};
- end
- //根据象限值计算乘法系数索引值
- reg [3:0]add_index[3:0];
- always @(posedge clk)
- begin
- if(win_valid==1'b1)
- begin
- if( (win_info[med_idx]==3'b000) |
- (win_info[med_idx]==
- 3'b110) )
- begin
- add_index[0]<= #1 4'd2;
- add_index[1]<= #1 4'd5;add_index[2]<= #1 4'd6;
- add_index[3]<= #1 4'd3;
- end
- else if((win_info[med_idx]==3'b001)|
- (win_info[med_idx]==3'b111))
- begin
- add_index[0]<= #1 4'd2;
- add_index[1]<= #1 4'd1;
- add_index[2]<= #1 4'd6;
- add_index[3]<= #1 4'd7;
- end
- else if((win_info[med_idx]==3'b011)|
- (win_info[med_idx]==3'b101))
- begin
- add_index[0]<= #1 4'd0;
- add_index[1]<= #1 4'd1;
- add_index[2]<= #1 4'd8;
- add_index[3]<= #1 4'd7;
- end
- else
- begin
- add_index[0]<= #1 4'd0;
- add_index[1]<= #1 4'd3;
- add_index[2]<= #1 4'd8;
- add_index[3]<= #1 4'd5;
- end
- end//根据极大值公式进行插值计算 ,计算开销3个时钟
- reg [7:0]nms_result;
- reg [2*DW_OUT-1:0]nms_max_a4;
- reg [2*DW_OUT-1:0]nms_max_a4_r;
- reg [2*DW_OUT-1:0]nms_add1;
- reg [2*DW_OUT-1:0]nms_add2;
- reg [2*DW_OUT-1:0]nms_add3;
- reg [2*DW_OUT-1:0]nms_add4;
- reg [2*DW_OUT:0]nms_add5;
- reg [2*DW_OUT:0]nms_add6;
- always @(posedge clk)
- begin
- if(win_valid_r[0]==1'b1)
- begin
- nms_max_a4 <= #1 win_r[med_idx]*win_max[med_idx];
- nms_add1 <= #1
- win_r[add_index[0]]*win_min[med_idx];
- nms_add2 <= #1 win_r[add_index[1]]*
- (win_max[med_idx]-win_min
- [med_idx]);
- nms_add3 <= #1
- win_r[add_index[2]]*win_min[med_idx];
- nms_add4 <= #1 win_r[add_index[3]]*
- (win_max[med_idx]-win_min
- [med_idx]);
- end
- if(win_valid_r[1]==1'b1)begin
- nms_max_a4_r <= #1 nms_max_a4;
- nms_add5 <= #1 nms_add1 + nms_add2;
- nms_add6 <= #1 nms_add3 + nms_add4;
- end
- if(win_valid_r[2]==1'b1)
- begin
- if(nms_max_a4_r == {2*DW_OUT{1'b0}})
- nms_result <= 8'd0;
- else if( (nms_max_a4_r >= nms_add5) &&
- (nms_max_a4_r >=nms_add6))
- nms_result <= 8'd128;
- else
- nms_result <= 8'd0;
- end
- end
- //缓存极大值结果,用来与模值结果对齐
- wire nms_valid;
- wire nms_vsync;
- wire nms_is_boarder;
- wire [7:0]nms_data;
- wire [KSZ*KSZ*8-1:0]nms_data_temp;
- win_buf #(8,KSZ,IH,IW)
- buf_nms(
- .rst_n(rst_n),
- .clk(clk),
- .din_valid(win_valid_r[3]),.din(nms_result),
- .dout(nms_data_temp),
- .dout_org(nms_data),
- .vsync(vsync),
- .vsync_out(nms_vsync),
- .is_boarder(nms_is_boarder),
- .dout_valid(nms_valid)
- );
- //缓存模值结果,来获得其3*3邻域
- wire [KSZ*KSZ*DW-1:0]mudule_temp;
- wire [DW-1:0]mudule_org;
- wire mudule_valid;
- wire mudule_vsync;
- wire mudule_is_boarder;
- win_buf #(DW,KSZ,IH,IW)
- mudule_buf(
- .rst_n(rst_n),
- .clk(clk),
- .din_valid(win_valid_r[3]),
- .din(mudule_reg[3]),
- .dout(mudule_temp),
- .dout_org(mudule_org),
- .vsync(vsync),
- .vsync_out(mudule_vsync),
- .is_boarder(mudule_is_boarder),
- .dout_valid(mudule_valid)
- );//邻域查找电路 在当前模值的邻域内查找是否有大于高阈值的邻
- 域点,如果有,则将结果
- //置1,需要两个时钟计算开销
- wire mudule_result_temp[0:7];
- assign mudule_result_temp[0]= (mudule_data[0]>= ThrHigh)?
- 1'b1:1'b0;
- assign mudule_result_temp[1]= (mudule_data[1]>= ThrHigh)?
- 1'b1:1'b0;
- assign mudule_result_temp[2]= (mudule_data[2]>= ThrHigh)?
- 1'b1:1'b0;
- assign mudule_result_temp[3]= (mudule_data[3]>= ThrHigh)?
- 1'b1:1'b0;
- assign mudule_result_temp[4]= (mudule_data[5]>= ThrHigh)?
- 1'b1:1'b0;
- assign mudule_result_temp[5]= (mudule_data[6]>= ThrHigh)?
- 1'b1:1'b0;
- assign mudule_result_temp[6]= (mudule_data[7]>= ThrHigh)?
- 1'b1:1'b0;
- assign mudule_result_temp[7]= (mudule_data[8]>= ThrHigh)?
- 1'b1:1'b0;
- wire mudule_result;
- reg mudule_result_tmp[0:6];
- always @(posedge clk)
- begin
- if(nms_valid==1'b1)
- beginmudule_result_tmp[0] <= #1 mudule_result_temp[0]
- |mudule_result_temp[1];
- mudule_result_tmp[1] <= #1 mudule_result_temp[2]
- |mudule_result_temp[3];
- mudule_result_tmp[2] <= #1 mudule_result_temp[4]
- |mudule_result_temp[5];
- mudule_result_tmp[3] <= #1 mudule_result_temp[6]
- |mudule_result_temp[7];
- end
- if(nms_valid_r[0]==1'b1)
- begin
- mudule_result_tmp[4]<=#1
- mudule_result_tmp[0]|mudule_result_tmp[1];
- mudule_result_tmp[5] <= #1 mudule_result_tmp[2]
- |mudule_result_tmp[3];
- end
- if(nms_valid_r[1]==1'b1)
- begin
- mudule_result_tmp[6]<=#1
- mudule_result_tmp[4]|mudule_result_tmp[5];
- end
- end
- assign mudule_result = mudule_result_tmp[6];
- //最后结果计算:大于高阈值直接置1,小于低阈值直接置0。
- 在两者之间,若查找到其邻域内有高于高阈值的点,则置1,否则置
- 零。
- reg [DW-1:0]dout_temp;reg [DW-1:0]mudule_org_r;
- reg [DW-1:0]mudule_org_r2;
- reg [8-1:0]nms_data_r;
- reg [8-1:0]nms_data_r2;
- always @(posedge clk)
- begin
- nms_data_r <= #1 nms_data;
- nms_data_r2 <= #1 nms_data_r;
- mudule_org_r <= #1 mudule_org;
- mudule_org_r2 <= #1 mudule_org_r;
- end
- always @(posedge clk)
- begin
- if(nms_valid_r[1]==1'b1)
- begin
- if(nms_data_r2==8'd128)
- begin
- if(mudule_org_r2 >= ThrHigh)
- dout_temp <= {{DW-8{1'b0}},8'd128};
- else if(mudule_org_r2 <= ThrLow)
- dout_temp <= {DW{1'b0}};
- else
- begin
- if(mudule_result == 1'b1)
- dout_temp <= {{DW-8{1'b0}},8'd128};
- else
- dout_temp <= {DW{1'b0}};end
- end
- else
- dout_temp <= {DW{1'b0}};
- end
- end
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
本模块的大部分模块已经在前面的章节中仿真过了,因此,在这 里我们只列出二维图像的仿真结果。图10-29(b)图像是对图10- 29(a)图像进行高阈值为20、低阈值为10的Canny算子运算后的结 果。
由图10-29可以看出,我们的设计达到了预期的目的。
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制式广播。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。