5.二维形态学Tophat运算模块(Morph_Tophat_2D) 本模块需要调用一个开运算模块,并将输入数据流与开运算的结 果进行对齐后进行一个减法运算。 模块定义如下:
module Morph_Tophat_2D(
din, //输入数据流
dout_valid, //输出数据有效
dout, //输出数据流
rst_n, //异步复位信号
din_valid, //输入数据有效
vsync, //输入场同步
vsync_out, //输出场同步clk //同步时钟信号
);
parameter DW = 14; //数据位宽
parameter KSZ = 7; //处理尺寸
parameter IW = 640; //图像宽度
parameter IH = 512; //图像高度
input [DW-1:0] din;
output dout_valid;
output [DW-1:0]dout;
input rst_n;
input din_valid;
input vsync;
output vsync_out;
input clk;
关键代码如下:
localparam radius = ((KSZ >> 1));
localparam latency = 11;
wire open_valid;
wire open_out;
wire [DW-1:0] dout_open;
reg [DW-1:0] din_delay[0:latency];
reg [latency:0]din_valid_delay;
reg rst_all;
reg [DW-1:0] line_din[0:KSZ-2];
wire [DW-1:0] line_dout[0:KSZ-2];
wire [KSZ-2:0] line_empty;
wire [KSZ-2:0] line_full;wire [KSZ-2:0] line_rden;
reg [KSZ-2:0] line_wren;
wire [9:0] line_count[0:KSZ-2];
reg [KSZ-2:0] buf_pop_en;
reg [15:0] out_pixel_cnt;
reg [10:0] out_line_cnt;
wire is_boarder;
reg [DW-1:0] dout_temp_r;
reg dout_valid_temp_r;
reg [DW-1:0] dout_temp;
reg dout_valid_temp;
wire [13:0] data_temp1;
wire erode_vsync;
wire erode_valid;
wire [DW-1:0] erode_out;
wire vsync_out_tmp1;
assign vsync_out = vsync_out_tmp1;
//帧同步复位信号
always @(posedge clk or negedge rst_n)
if (((~(rst_n))) == 1'b1)
rst_all <= 1'b1;
else
begin
if (vsync == 1'b1)
rst_all <= 1'b1;
else
rst_all <= 1'b0;end
//首先进行开运算
Morph_Open_2D #(DW,KSZ,IH,IW)
morph_open(
.rst_n(rst_n),
.clk(clk),
.din_valid(din_valid),
.din(din),
.dout(dout_open), //开运算结果
.dbg_vsync(erode_vsync),
.dbg_valid(erode_valid),
.dbg_out(erode_out),
.vsync(vsync),
.vsync_out(vsync_out_tmp1),
.dout_valid(open_valid) //开运算后数据有效信
号
);
//输入有效缓存用于时序对齐
always @(posedge clk)
begin
if (rst_all == 1'b1)
din_valid_delay <= {latency+1{1'b0}};
else
din_valid_delay<=({din_valid_delay[latency-
1:0],din_valid});
end
//缓存输入数据latency个时钟generate
begin : xhdl1
genvar i;
for (i = 0; i <= latency; i = i + 1)
begin : small_buf_delay
if (i == 0)
begin : MAP1
always @(posedge clk)
begin
if (rst_all == 1'b1)
din_delay[i]<= {DW{1'b0}};
else if (din_valid == 1'b1)
din_delay[i]<= din;
end
end
if ((~(i == 0)))
begin : MAP2
always @(posedge clk)
begin
if (rst_all == 1'b1)
din_delay[i]<= {DW{1'b0}};
else if ((din_valid_delay[i - 1]) ==
1'b1)
din_delay[i]<= din_delay[i - 1];
end
end
endend
endgenerate
generate
begin : xhdl2
genvar i;
for (i = 0; i <= KSZ - 2; i = i + 1)
begin : line_buf_inst
if (i == 0)
begin : MAP3
always @(posedge clk)
begin
if (rst_all == 1'b1)
begin
line_din[i]<= {DW{1'b0}};
line_wren[i]<= 1'b0;
end
else
begin
line_wren[i]<= din_valid_delay[latency];
line_din[i]<= din_delay[latency];
//第一个行缓存的输入为缓存后的输入数据流
end
end
end
//其他的行缓存接成菊花链式结构
if ((~(i == 0)))
begin : MAP4always @(posedge clk)
begin
if (rst_all == 1'b1)
begin
line_din[i]<= {DW{1'b0}};
line_wren[i]<= 1'b0;
end
else
begin
line_din[i]<= line_dout[i - 1];
line_wren[i]<= #1 line_rden[i - 1];
end
end
end
assign line_rden[i]=buf_pop_en[i]&
(din_valid_delay[latency]
| open_valid);
//流水线装载完成时刻
always @(posedge clk)
begin
if (rst_all == 1'b1)
buf_pop_en[i]<= #1 1'b0;
else if (line_count[i]== IW)
buf_pop_en[i]<= #1 1'b1;
end
//例化行缓存
line_buffer line_buf_inst(.rst(rst_all),
.clk(clk),
.din(line_din[i]),
.dout(line_dout[i]),
.wr_en(line_wren[i]),
.rd_en(line_rden[i]),
.empty(line_empty[i]),
.full(line_full[i]),
.count(line_count[i])
);
end
end
endgenerate
//计算Tophat运算结果,输入数据减去开运算结果
always @(posedge clk)
begin
if (open_valid == 1'b1)
begin
if (dout_open >= line_dout[KSZ - 2])
dout_temp <= {DW{1'b0}};
else
dout_temp <= line_dout[KSZ - 2]-
dout_open;
end
end
//输出数据有效产生
always @(posedge clk)begin
if (rst_all == 1'b1)
begin
dout_valid_temp <= 1'b0;
dout_valid_temp_r <= 1'b0;
end
else
begin
dout_valid_temp <= open_valid;
dout_valid_temp_r <= dout_valid_temp;
end
end
//边界清零
assign data_temp1 = ((is_boarder == 1'b1)) ?
{DW{1'b0}} :
dout_temp;
//输出数据
always @(posedge clk)
begin
if (dout_valid_temp == 1'b1)
dout_temp_r <= data_temp1;
else
dout_temp_r <= #1 {DW{1'b0}};
end
assign dout = dout_temp_r;
assign dout_valid = dout_valid_temp_r;
//输出像素计数和输出行计数always @(posedge clk)
begin
if (rst_all == 1'b1)
begin
out_pixel_cnt <= #1 {16{1'b0}};
out_line_cnt <= #1 {11{1'b0}};
end
else
begin
if(dout_valid_temp_r==1'b1&(( ~
(dout_valid_temp)))==1'b1)
out_line_cnt <= #1 out_line_cnt +
11'b00000000001;
else
out_line_cnt <= #1 out_line_cnt;
if(dout_valid_temp_r==1'b1&(( ~
(dout_valid_temp)))==1'b1)
out_pixel_cnt <= #1 {16{1'b0}};
else if (dout_valid_temp == 1'b1)
out_pixel_cnt<=#1
out_pixel_cnt+16'b0000000000000001;
end
end
//边界判决
assign is_boarder = ((dout_valid_temp == 1'b1 &
(out_pixel_cnt <=((radius - 1)) | out_pixel_cnt >= ((IW- radius)) | out_line_cnt <= ((radius- 1)) |
out_line_cnt >= ((IH - radius))))) ? 1'b1 : 1'b0;
9.3.4 仿真及调试结果
1.TestBench设计 将5.2.3节捕获到的视频数据流cap_dat,cap_vsync,cap_dvalid 接入Tophat滤波模块的输入端,同时,将滤波后的数据写入文件,在 VC中读取文件并显示处理完后的图像。 TestBench关键代码如下:
parameter ksz_tophat=7; //Tophat 滤波窗口尺寸
Morph_Tophat_2D #(14,ksz_tophat,iw,ih)
tophat_2d(
.din(cap_dat), //输入数据流
.dout_valid(tophat_dvalid), //输出行同步
.dout(tophat_data), //输出数据流
.rst_n(reset_l), //异步复位
.din_valid(cap_dvalid), //输入行同步
.vsync(cap_vsync), //输入场同步
.vsync_out(tophat_vsync), //输出场同步
.clk(cap_clk) //采集时钟
);
wire tophat_dvalid;
wire [DW-1:0]tophat_dat;
wire tophat_vsync;
integer fp_tophat =0; //文件指针
integer cnt_tophat =0; //文件偏移always @(posedge cap_clk or posedge tophat_vsync )
if (((~(tophat_vsync))) == 1'b0)
cnt_tophat=0; //新的一帧到来时回到文件头
else
begin
if (tophat_dvalid == 1'b1)
begin
fp_tophat =
$fopen("txt_out/tophat_dout.txt","r+");
//打开当前文件
$fseek(fp_tophat,cnt_tophat,0); //寻址
$fdisplay(fp_tophat,"%04x\n",tophat_data);
//将当前数据写入文件
$fclose(fp_tophat);
cnt_tophat<=cnt_tophat+6; //移动到下一个待写
位置
end
end
2.模块仿真结果和MinMax模块
截取的仿真图如图9-23所示。
图9-23 MinMax模块仿真图
设 竖 线 所 在 时 刻 为 t , 则 din_a,din_b,min_tmp,max_tmp,dout_max,dout_min连续10个时钟的数 据如表9-3所示(按膨胀操作,×表示无关项)。
设 竖 线 所 在 时 刻 为 t , 则 din,reg_din,max(0),max(1),max(2),max(3),dout连续10个时钟的数 据如表9-4所示(按膨胀操作,×表示无关项)。 表9-4 一维膨胀/腐蚀模块仿真结果
仿真结果与表9-4计算结果一致,可见代码设计正确。 4.二维形态学膨胀/腐蚀模块 对二维的仿真结果进行验证,用图像来说明是最直观不过的了。 图9-25是对图9-8用7×7的窗口进行膨胀之后的联合仿真结果。 由图9-25可见,高亮区域得到了扩充,实现了预期的膨胀功能。 5.Tophat形态学滤波模块 图9-26是对图9-8用7×7的窗口进行Tophat滤波之后的联合仿真结 果。仿真结果与用VC处理后的结果保持一致。
6.算法实时性仿真 图9-27为输入数据流cap_dat、腐蚀结果、膨胀结果与Tophat滤波 结果的时序仿真图。
仿真结果也验证了9.3.1节中对算法实时性的预测。