本帖最后由 FPGA课程 于 2024-10-17 13:24 编辑
软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1 算子模板简介
在图像处理过程中,常常需要对图像进行滤波操作,进行滤波操作需要使用算子模板,也可以称之为扫描窗模 板,一般有 3x3、5x5、7x7 等模板形式。本文重在阐述算子模板的概念及使用 verilog 来描述其产生过程。下面咱们 从图像上来认识算子模板。 如图所示,展示了一个宽度为 15 个像素,高度为 8 个像素的图片,每个白色方块代表一个像素。
实际的图像处理过程中会选定一个模板,假设使用 3x3 的模板,如图所示,灰色代表图像的边界,蓝色框表示 3x3 的模板,对整幅图像进行扫窗操作,在图之中标注了第一个和最后一个模板扫描的操作位置。
我们从图中可以观察到边界一行的像素是无法进行运算的,这个也是扫窗的一个缺点,无法对边界进行处理, 而且随着算子的变大边界无法处理的像素也会变多。后面进行具体操作时,会提出一种补充处理的方法。如图所示, 对浅灰色的边界进行扩展,就是图中的深灰色部分内容,一般简单处理,有复制边界为零的,也可以将原来的边界 进行复制。 使用 5x5 的模板,如下图所示:
使用 5x5 的模板边界进行扩展 前面已经分析了算子模板的原理,下面来介绍一下如何使用 verilog 来描述。我们使用FIFO 来缓存图像的行数 据,如果取 3x3 的模板,那么至少需要两个深度大于图像行数据的长度的 FIFO,通过首尾相连的形式来缓存两行 数据,等第三行数据到来之时,同时输出三行数据。注意,最后的 FIFO 输出数据是最早的数据,也就是第一行的 数据,如图所示:
2 设计分析2.1Verilog代码分析 第一节介绍了 3x3 的模板和 5x5 的模板,本节描述,如何控制 FIFO 使其数据进行对齐的。 - parameter H_ACTIVE = 1280; //图像宽度
- parameter V_ACTIVE = 720; //图像高度
- reg [10:0] h_cnt;
- reg [10:0] v_cnt;
- wire [7:0] fifo_1_in;
- wire fifo_1_wr_en;
- wire fifo_1_rd_en;
- wire [7:0] fifo_1_out;
- wire [7:0] fifo_2_in;
- wire fifo_2_wr_en;
- wire fifo_2_rd_en;
- wire [7:0] fifo_2_out;
- `ifdef TEMPLATE_5X5
- wire [7:0] fifo_3_in;
- wire fifo_3_wr_en;
- wire fifo_3_rd_en;
- wire [7:0] fifo_3_out;
- wire [7:0] fifo_4_in;
- wire fifo_4_wr_en;
- wire fifo_4_rd_en;
- wire [7:0] fifo_4_out;
- `endif
- //显示区域行计数
- always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- h_cnt <= 11'd0;
- end
- else if(i_en)
- begin
- if(h_cnt == H_ACTIVE - 1'b1)
- h_cnt <= 11'd0;
- else
- h_cnt <= h_cnt + 11'd1;
- end
- end
- //显示区域场计数
- always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- v_cnt <= 11'd0;
- end
- else if(h_cnt == H_ACTIVE - 1'b1)
- begin
- if(v_cnt == V_ACTIVE - 1'b1)
- v_cnt <= 11'd0;
- else
- v_cnt <= v_cnt + 11'd1;
- end
- end
- assign fifo_1_in = i_data;
- assign fifo_1_wr_en = (v_cnt < V_ACTIVE - 1) ? i_en : 1'b0;
- assign fifo_1_rd_en = (v_cnt > 0) ? i_en : 1'b0;
- assign fifo_2_in = fifo_1_out;
- assign fifo_2_wr_en = fifo_1_rd_en;
- assign fifo_2_rd_en = (v_cnt > 1) ? i_en : 1'b0;
- `ifdef TEMPLATE_5X5
- assign fifo_3_in = fifo_2_out;
- assign fifo_3_wr_en = fifo_2_rd_en;
- assign fifo_3_rd_en = (v_cnt > 2) ? i_en : 1'b0;
- assign fifo_4_in = fifo_3_out;
- assign fifo_4_wr_en = fifo_3_rd_en;
- assign fifo_4_rd_en = (v_cnt > 3) ? i_en : 1'b0;
- `endif
- fifo_generator_0 u_fifo_1(
- .clk (i_clk ),
- .srst (!i_rst_n ),
- .din (fifo_1_in ),
- .wr_en (fifo_1_wr_en ),
- .rd_en (fifo_1_rd_en ),
- .dout (fifo_1_out ),
- .full ( ),
- .empty ( ),
- .data_count ( )
- );
- fifo_generator_0 u_fifo_2(
- .clk (i_clk ),
- .srst (!i_rst_n ),
- .din (fifo_2_in ),
- .wr_en (fifo_2_wr_en ),
- .rd_en (fifo_2_rd_en ),
- .dout (fifo_2_out ),
- .full ( ),
- .empty ( ),
- .data_count ( )
- );
- `ifdef TEMPLATE_5X5
- fifo_generator_0 u_fifo_3(
- .clk (i_clk ),
- .srst (!i_rst_n ),
- .din (fifo_3_in ),
- .wr_en (fifo_3_wr_en ),
- .rd_en (fifo_3_rd_en ),
- .dout (fifo_3_out ),
- .full ( ),
- .empty ( ),
- .data_count ( )
- );
- fifo_generator_0 u_fifo_4(
- .clk (i_clk ),
- .srst (!i_rst_n ),
- .din (fifo_4_in ),
- .wr_en (fifo_4_wr_en ),
- .rd_en (fifo_4_rd_en ),
- .dout (fifo_4_out ),
- .full ( ),
- .empty ( ),
- .data_count ( )
- );
- `endif
- `ifdef TEMPLATE_3X3
- always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- o_temp_11 <= 8'd0;
- o_temp_12 <= 8'd0;
- o_temp_13 <= 8'd0;
-
- o_temp_21 <= 8'd0;
- o_temp_22 <= 8'd0;
- o_temp_23 <= 8'd0;
-
- o_temp_31 <= 8'd0;
- o_temp_32 <= 8'd0;
- o_temp_33 <= 8'd0;
- end
- else
- begin
- o_temp_11 <= o_temp_12;
- o_temp_12 <= o_temp_13;
- o_temp_13 <= fifo_2_out;
-
- o_temp_21 <= o_temp_22;
- o_temp_22 <= o_temp_23;
- o_temp_23 <= fifo_1_out;
-
- o_temp_31 <= o_temp_32;
- o_temp_32 <= o_temp_33;
- o_temp_33 <= i_data;
- end
- end
- always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- o_en <= 1'b0;
- end
- else if((v_cnt > 1)&&(h_cnt > 1))
- begin
- o_en <= i_en;
- end
- else
- begin
- o_en <= 1'b0;
- end
- end
- `endif
- `ifdef TEMPLATE_5X5
- always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- o_temp_11 <= 8'd0;
- o_temp_12 <= 8'd0;
- o_temp_13 <= 8'd0;
- o_temp_14 <= 8'd0;
- o_temp_15 <= 8'd0;
- o_temp_21 <= 8'd0;
- o_temp_22 <= 8'd0;
- o_temp_23 <= 8'd0;
- o_temp_24 <= 8'd0;
- o_temp_25 <= 8'd0;
- o_temp_31 <= 8'd0;
- o_temp_32 <= 8'd0;
- o_temp_33 <= 8'd0;
- o_temp_34 <= 8'd0;
- o_temp_35 <= 8'd0;
- o_temp_41 <= 8'd0;
- o_temp_42 <= 8'd0;
- o_temp_43 <= 8'd0;
- o_temp_44 <= 8'd0;
- o_temp_45 <= 8'd0;
- o_temp_51 <= 8'd0;
- o_temp_52 <= 8'd0;
- o_temp_53 <= 8'd0;
- o_temp_54 <= 8'd0;
- o_temp_55 <= 8'd0;
- end
- else
- begin
- o_temp_11 <= o_temp_12;
- o_temp_12 <= o_temp_13;
- o_temp_13 <= o_temp_14;
- o_temp_14 <= o_temp_15;
- o_temp_15 <= fifo_4_out;
-
- o_temp_21 <= o_temp_22;
- o_temp_22 <= o_temp_23;
- o_temp_23 <= o_temp_24;
- o_temp_24 <= o_temp_25;
- o_temp_25 <= fifo_3_out;
-
- o_temp_31 <= o_temp_32;
- o_temp_32 <= o_temp_33;
- o_temp_33 <= o_temp_34;
- o_temp_34 <= o_temp_35;
- o_temp_35 <= fifo_2_out;
-
- o_temp_41 <= o_temp_42;
- o_temp_42 <= o_temp_43;
- o_temp_43 <= o_temp_44;
- o_temp_44 <= o_temp_45;
- o_temp_45 <= fifo_1_out;
-
- o_temp_51 <= o_temp_52;
- o_temp_52 <= o_temp_53;
- o_temp_53 <= o_temp_54;
- o_temp_54 <= o_temp_55;
- o_temp_55 <= i_data;
- end
- end
- always@(posedge i_clk or negedge i_rst_n)
- begin
- if(!i_rst_n)
- begin
- o_en <= 1'b0;
- end
- else if((v_cnt > 3)&&(h_cnt > 3))
- begin
- o_en <= i_en;
- end
- else
- begin
- o_en <= 1'b0;
- end
- end
- `endif
- endmodule
复制代码
3 仿真及结果3.1Vivadosim实验结果 3x3 的模板仿真图:
5x5 的模板仿真图:
|