Matlab、ISE联合开发实例之中值滤波(二)FPGA硬件架构实现

来源:互联网 发布:数据江湖txt精校版 编辑:程序博客网 时间:2024/05/22 14:28

声明:主要程序及架构思想均来自徐文波、田耘《Xilinx FPGA开发实用教程(第二版)》,本人在学习过程中按照书上指导将其实现,将其拿出与初学者交流分享。所有步骤均经过验证(并修正了书上若干细节小错误)。O(∩_∩)O~


硬件架构要充分考虑硬件自身的特点,比如说并行性。这里我们要发现中值滤波的特点,实际上仅仅为了找出9个数的中值是不需要排序的。

算法如下:(后面有时间再画一张图说明)

9个数,先分为3组分别找每组的最小值MIN、中间值MED、最大值MAX(对于3*3小矩阵,按行或列比较即可)

然后将三组的最小值MIN1、MIN2、MIN3合成一组,找出其最大值,记为A1

将三组的中间值MED1、MED2、MED3合成一组,找出其中间值,记为A2

将三组的最大值MAX1、MAX2、MAX3合成一组,找出其最小值,记为A3

最后,找出A1、A2、A3的中间值,就是所求的9个数的中间值。大家只要画个图就发现这种方法很利于并行化处理。

接下来是verilog实现代码,zhongzhilvbo是主模块,其中调用了uutcompare8比较每个数,然后用case语句来判断MIN、MED和MAX

module zhongzhilvbo(    clk_pixel, rst_n,  din1, din2, din3, din4, din5, din6, din7, din8, din9, dout    );    input         clk_pixel; input         rst_n;    input  [7:0] din1, din2, din3, din4, din5, din6, din7, din8, din9;    output [7:0]  dout;  reg    [7:0]  dout;    wire   d12, d13, d23;    wire   d45, d46, d56;    wire   d78, d79, d89;     wire   dd12, dd13, dd23;    wire   dd45, dd46, dd56;    wire   dd78, dd79, dd89;   wire   ddd12, ddd13, ddd23;     reg [7:0]  dtm11, dtm12, dtm13, dtm21, dtm22, dtm23, dtm31, dtm32, dtm33; reg [7:0]  dtm221, dtm222, dtm223;  // First always @(posedge clk_pixel) begin    if(!rst_n) begin//同步复位    dtm11 <= 0; dtm12 <= 0;    dtm13 <= 0; dtm21 <= 0;    dtm22 <= 0; dtm23 <= 0; dtm31 <= 0;     dtm32 <= 0; dtm33 <= 0;  end else begin    //3个一组进行大小比较,d12=0表示din1>din2,以此类推 //其中dtm11为3者中最大值,dtm12为中间值,dtm13为最小值          case({d12, d13, d23})    3'b000: begin    dtm11 <= din3; dtm12 <= din2; dtm13 <= din1; end 3'b001: begin    dtm11 <= din2; dtm12 <= din3; dtm13 <= din1;  end 3'b011: begin    dtm11 <= din2; dtm12 <= din1; dtm13 <= din3;  end 3'b100: begin    dtm11 <= din3; dtm12 <= din1; dtm13 <= din2;  end 3'b110: begin    dtm11 <= din1; dtm12 <= din3; dtm13 <= din2;  end 3'b111: begin    dtm11 <= din1; dtm12 <= din2; dtm13 <= din3;  end             default: begin    dtm11 <= din3; dtm12 <= din1; dtm13 <= din2;             end  endcase     //3个一组进行大小比较 //其中dtm21为3者中最大值,dtm22为中间值,dtm23为最小值           case({d45, d46, d56})    3'b000: begin    dtm21 <= din6; dtm22 <= din5; dtm23 <= din4; end 3'b001: begin    dtm21 <= din5; dtm22 <= din6; dtm23 <= din4;  end 3'b011: begin    dtm21 <= din5; dtm22 <= din4; dtm23 <= din6;  end 3'b100: begin    dtm21 <= din6; dtm22 <= din4; dtm23 <= din5;  end 3'b110: begin    dtm21 <= din4; dtm22 <= din6; dtm23 <= din5;  end 3'b111: begin    dtm21 <= din4; dtm22 <= din5; dtm23 <= din6;  end             default: begin    dtm21 <= din6; dtm22 <= din4; dtm23 <= din5;             end  endcase    //3个一组进行大小比较 //其中dtm31为3者中最大值,dtm32为中间值,dtm33为最小值          case({d78, d79, d89})    3'b000: begin    dtm31 <= din9; dtm32 <= din8; dtm33 <= din7; end 3'b001: begin    dtm31 <= din8; dtm32 <= din9; dtm33 <= din7;  end 3'b011: begin    dtm31 <= din8; dtm32 <= din7; dtm33 <= din9;  end 3'b100: begin    dtm31 <= din9; dtm32 <= din7; dtm33 <= din8;  end 3'b110: begin    dtm31 <= din7; dtm32 <= din9; dtm33 <= din8;  end 3'b111: begin    dtm31 <= din7; dtm32 <= din8; dtm33 <= din9;  end             default: begin    dtm31 <= din9; dtm32 <= din7; dtm33 <= din8;             end  endcase  end end   // Second  // 进行第二轮比较 always @(posedge clk_pixel) begin    if(!rst_n) begin          dtm221 <= 0;          dtm222 <= 0;          dtm223 <= 0;  end else begin    // min // 挑3个最小值中的最大值    case({dd12, dd13, dd23})    3'b000, 3'b001: dtm221 <= dtm11; 3'b011, 3'b111: dtm221 <= dtm31; default: dtm221 <= dtm21; endcase  //mid //挑3个中间值中的中间值 case({dd45, dd46, dd56})    3'b000, 3'b111: dtm222 <= dtm22; 3'b001, 3'b110: dtm222 <= dtm32; default: dtm222 <= dtm12;  endcase  //max //挑3个最大值中间的最小值 case({dd78, dd79, dd89})    3'b110, 3'b111: dtm223 <= dtm13; 3'b000, 3'b100: dtm223 <= dtm33; default: dtm223 <= dtm23;     endcase endend //Third//最后一轮,输出3个中的中间值 always @(posedge clk_pixel) begin    if(!rst_n) begin dout <= 0; end else begin    case({ddd12, ddd13, ddd23})    3'b000, 3'b111: dout <= dtm222; 3'b001, 3'b110: dout <= dtm223; default: dout <= dtm221; endcase end    end //例化8位比较器 uutcompare8 inst_11_uutcompare8(.qa_gt_b(d12), .a(din1), .b(din2)    );  uutcompare8 inst_12_uutcompare8( .qa_gt_b(d13), .a(din1), .b(din3)    );  uutcompare8 inst_13_uutcompare8(.qa_gt_b(d23), .a(din2), .b(din3)    ); uutcompare8 inst_14_uutcompare8(.qa_gt_b(d45), .a(din4), .b(din5)    );  uutcompare8 inst_15_uutcompare8(.qa_gt_b(d46), .a(din4), .b(din6)    );  uutcompare8 inst_16_uutcompare8(.qa_gt_b(d56), .a(din5), .b(din6)    );  uutcompare8 inst_17_uutcompare8(.qa_gt_b(d78), .a(din7), .b(din8)    );  uutcompare8 inst_18_uutcompare8( .qa_gt_b(d79), .a(din7), .b(din9)    );  uutcompare8 inst_19_uutcompare8(.qa_gt_b(d89), .a(din8), .b(din9)    ); uutcompare8 inst_21_uutcompare8(.qa_gt_b(dd12), .a(dtm11), .b(dtm21)    );  uutcompare8 inst_22_uutcompare8( .qa_gt_b(dd13), .a(dtm11), .b(dtm31)    );  uutcompare8 inst_23_uutcompare8(.qa_gt_b(dd23), .a(dtm21), .b(dtm31)    ); uutcompare8 inst_24_uutcompare8(.qa_gt_b(dd45), .a(dtm12), .b(dtm22)    );  uutcompare8 inst_25_uutcompare8(.qa_gt_b(dd46), .a(dtm12), .b(dtm32)    );  uutcompare8 inst_26_uutcompare8(.qa_gt_b(dd56), .a(dtm22), .b(dtm32)    );  uutcompare8 inst_27_uutcompare8(.qa_gt_b(dd78), .a(dtm13), .b(dtm23)    );  uutcompare8 inst_28_uutcompare8( .qa_gt_b(dd79), .a(dtm13), .b(dtm23)    );  uutcompare8 inst_29_uutcompare8(.qa_gt_b(dd89), .a(dtm23),.b(dtm33)    );     uutcompare8 inst_31_uutcompare8(.qa_gt_b(ddd12), .a(dtm221), .b(dtm222)    );  uutcompare8 inst_32_uutcompare8( .qa_gt_b(ddd13), .a(dtm221), .b(dtm223)    );  uutcompare8 inst_33_uutcompare8(.qa_gt_b(ddd23), .a(dtm222), .b(dtm223)    ); endmodule

模块uutcompare8中调用了Xilinx ISE中的IP核compare8(也正是这个原因后面尝试用Modelsim仿真没有成功,报错说这个IP核resolve不了)

module uutcompare8(  qa_gt_b, a, b);   output qa_gt_b;  input [7 : 0] a;  input [7 : 0] b;    compare8 inst_compare8(.a_gt_b(qa_gt_b), .a(a), .b(b));endmodule

综合之后的RTL电路图

内部结构图比较大,截一小部分放在这里:



接下来编写测试文件(TestBench)来对上述电路结构进行波形仿真。

1.仿真软件是ISE内置的Isim,本来想调用Modelsim,但可能由于IP核的原因没有成功。实际上Isim也挺不错的。同时工程Project——Design Properties中要将Simulator设为Isim(VHDL/Verilog)。

2.测试文件中的数据是随意生成的,目的主要是通过输出波形观察中值滤波是否正确执行。

下面是测试文件代码:

module tb_zhongzhilvbo;// Inputsreg clk_pixel;reg rst_n;reg [7:0] din1;reg [7:0] din2;reg [7:0] din3;reg [7:0] din4;reg [7:0] din5;reg [7:0] din6;reg [7:0] din7;reg [7:0] din8;reg [7:0] din9;// Outputswire [7:0] dout;// Instantiate the Unit Under Test (UUT)zhongzhilvbo uut (.clk_pixel(clk_pixel), .rst_n(rst_n), .din1(din1), .din2(din2), .din3(din3), .din4(din4), .din5(din5), .din6(din6), .din7(din7), .din8(din8), .din9(din9), .dout(dout));initial begin// Initialize Inputsclk_pixel = 0;rst_n = 0;din1 = 1;din2 = 2;din3 = 3;din4 = 4;din5 = 5;din6 = 6;din7 = 7;din8 = 8;din9 = 9;// Wait 100 ns for global reset to finish#100;      rst_n = 1;  // Add stimulus hereendalways #8 clk_pixel = ~clk_pixel;always #16 begindin1 = din1 + 188;din2 = din2 + 11;din3 = din3 + 26;din4 = din4 + 37;din5 = din5 + 47;din6 = din6 + 89;din7 = din7 + 125;din8 = din8 + 137;din9 = din9 + 159;end      endmodule

选中Design窗口顶部View选项中的Simulation,选择上述测试文件,这时在Process窗口中显示的是ISim Simulator,点击Behavioral Check Syntax,然后点击Simulate Behavioral Model,ISE会自动调用ISim进行仿真,仿真波形如下:



从以上波形可以看出中值滤波是正确实现了的,并且还可以看出延时。(图中红色框标注的是对应的输入和输出)


到此为止,我们就用硬件架构完成了中值滤波。但注意到我们这里的测试文件相当于是自己随便产生的一些数据,验证的时候也是凭自己眼睛看输出波形。那么对于真实的图片数据如何输入进来,或者说大数据量时如何测试和验证?这就需要用到matlab和ISE联合开发,具体请看下一篇。O(∩_∩)O~