大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。
今天给大侠带来基于FPGA的中值滤波器设计,附源码,获取源码,请在“FPGA技术江湖”公众号内回复“中值滤波器设计源码”,可获取源码文件。话不多说,上货。
设计背景
在图像采集、转换和传输的过程中,由于成像系统、传输介质和工作环境等固有的缺陷,不可避免地产生各种类型的噪声,导致获取的图像往往与实际图像有差异。图像质量的下降使得图像后续处理(如边缘检测、图像分割、特征提取、模式识别等)产生困难,因此对噪声图像进行滤波是必要预处理过程,这可以使处理后的图像更适合观察或提取有用信息。但滤波算法在去除噪声的同时难免对图像造成一定程度的模糊,造成细节信息的丢失。中值滤波是对图像的低通滤波,可有效滤除高频噪声,增强图像清晰度。
设计原理
中值滤波是对一个滑动窗口内的诸像素灰度值排序,用其中值代替窗口中心象素的原来灰度值,它是一种非线性的图像平滑法,它对脉冲干扰级椒盐噪声(脉冲噪声)的抑制效果好,在抑制随机噪声的同时能有效保护边缘少受模糊。
本设计采用3*3的滑动窗口,先将3*3窗口中每一列数据进行从大到小的排序,列排序后,再对窗口中每一行的数据从大到小进行排序,之后再对窗口中对角线上的数据进行排序,得到中间值,即为9个数的中值。其示意图如下:
这种滤波算法,极大减少了比较的次数,提高了图像处理的速度,在FPGA上,不仅易于实现,而且占用了更少的片上资源。
这种滤波算法,极大减少了比较的次数,提高了图像处理的速度,在FPGA上,不仅易于实现,而且占用了更少的片上资源。
设计架构图
本设计可分为四个模块,分别是:ROM模块,用于存储处理图像的信息;3*3窗口生成模块,用于生成滤波的滑动窗口,得到窗口内的所有元素数据;计数器控制模块,主要用于获得中心像素点的地址信息;3*3中值滤波模块,主要用于得到某一中心像素点的3*3滑动窗口区域的灰度值的中值,作为中心像素点的值。
设计代码
medfilter顶层模块代码:
module medfilter(CLK,RSTn,Start_sig,Done_sig,Data_out);input CLK;input RSTn;input Start_sig;output Done_sig;output [7:0] Data_out;/********************************************************************/wire [17:0] rom_addr; //wire [7:0] rom_data; //// rom_512by512 rom_512by512_inst// (// .clka(CLK), //input clka;// .addra(rom_addr), //input-from;// .douta(rom_data) //output-to ;// );rom_512by512 rom_512by512_inst(.address(rom_addr), //input clka;.clock(CLK), //input-from;.q(rom_data) //output-to ;);/******************************************************************************///wire [7:0] win_data[8:0];wire [7:0] data_out0; //output-to ;wire [7:0] data_out1;wire [7:0] data_out2;wire [7:0] data_out3;wire [7:0] data_out4;wire [7:0] data_out5;wire [7:0] data_out6;wire [7:0] data_out7;wire [7:0] data_out8;wire win_done_sig;wire [9:0] column_addr_sig;wire [9:0] row_addr_sig;win3by3_gen win3by3_gen_inst (.CLK(CLK),.RSTn(RSTn),.center_pix_sig(win_start_sig), //input-from ;.cols(10'd512), // the column numbers of the input image.rows(10'd512), // the row numbers of the input image.rom_data_win(rom_data), //input-from ;.column_addr_sig(column_addr_sig), //input-from ; //output [9 : 0] addra;.row_addr_sig(row_addr_sig), //input-from ; //output [9 : 0] addra;.rom_addr_sig(rom_addr), //output-to ;.data_out0(data_out0), //output-to ;.data_out1(data_out1),.data_out2(data_out2),.data_out3(data_out3),.data_out4(data_out4),.data_out5(data_out5),.data_out6(data_out6),.data_out7(data_out7),.data_out8(data_out8),.win_data_done_sig(win_done_sig) //output-to U4/U3;);/******************************************************************************/counter_ctrl counter_ctrl_inst(.CLK(CLK),.RSTn(RSTn),.start_sig(Start_sig), //input-from top.nxt_pix_sig(win_done_sig), //input-from.cols(10'd512),.column_addr_sig(column_addr_sig), //output-to.row_addr_sig(row_addr_sig), //output-to.pix_done_sig(win_start_sig) //output-to);/*****************************************************************************/wire medfilt_done_sig;wire [7:0] medfilt_data_wire;medfilter3by3 medfilter3by3_inst(.CLK(CLK),.RSTn(RSTn),.win_data_sig(win_done_sig), //input-from;.medfilt_done_sig(medfilt_done_sig), //output-to;.data_in0(data_out0), //input-from ;.data_in1(data_out1),.data_in2(data_out2),.data_in3(data_out3),.data_in4(data_out4),.data_in5(data_out5),.data_in6(data_out6),.data_in7(data_out7),.data_in8(data_out8),.medfilt_data_out(medfilt_data_wire) //output-to top;);/*********************************************************************/wire Done_sig;wire [7:0] Data_out;assign Done_sig = medfilt_done_sig;assign Data_out = medfilt_data_wire;/**********************************************************************/endmodule
rom_512by512设计模块代码:
// synopsys translate_off`timescale 1 ps / 1 ps// synopsys translate_onmodule rom_512by512 (address,clock,q);input [17:0] address;input clock;output [7:0] q;`ifndef ALTERA_RESERVED_QIS// synopsys translate_off`endiftri1 clock;`ifndef ALTERA_RESERVED_QIS// synopsys translate_on`endifwire [7:0] sub_wire0;wire [7:0] q = sub_wire0[7:0];altsyncram altsyncram_component (.address_a (address),.clock0 (clock),.q_a (sub_wire0),.aclr0 (1'b0),.aclr1 (1'b0),.address_b (1'b1),.addressstall_a (1'b0),.addressstall_b (1'b0),.byteena_a (1'b1),.byteena_b (1'b1),.clock1 (1'b1),.clocken0 (1'b1),.clocken1 (1'b1),.clocken2 (1'b1),.clocken3 (1'b1),.data_a ({8{1'b1}}),.data_b (1'b1),.eccstatus (),.q_b (),.rden_a (1'b1),.rden_b (1'b1),.wren_a (1'b0),.wren_b (1'b0));defparamaltsyncram_component.address_aclr_a = "NONE",altsyncram_component.clock_enable_input_a = "BYPASS",altsyncram_component.clock_enable_output_a = "BYPASS",altsyncram_component.init_file = "medfilter2_re.mif",altsyncram_component.intended_device_family = "Cyclone IV E",altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO",altsyncram_component.lpm_type = "altsyncram",altsyncram_component.numwords_a = 262144,altsyncram_component.operation_mode = "ROM",altsyncram_component.outdata_aclr_a = "NONE",altsyncram_component.outdata_reg_a = "UNREGISTERED",altsyncram_component.widthad_a = 18,altsyncram_component.width_a = 8,altsyncram_component.width_byteena_a = 1;endmodule
counter_ctrl模块代码:
module counter_ctrl(CLK,RSTn,start_sig, //input-from topnxt_pix_sig, //input-from --start next center point pixelcols,column_addr_sig, //outputrow_addr_sig, //output-topix_done_sig //output-to);input CLK;input RSTn;input start_sig;input nxt_pix_sig;input [9:0] cols;output pix_done_sig;output [9:0] column_addr_sig;output [9:0] row_addr_sig;/***********************************************************************************************/reg isCtrlDone;//reg isWinStart;reg [17:0] imk; //The k-th pixel of the imagereg [9:0] row_addr; // The row of the centeral pixelreg [9:0] column_addr; // The column of the centeral pixelreg start_sig_d;wire start_sig_rising_vld;always @ (posedge CLK or negedge RSTn) //Asynchronous resetif (!RSTn)start_sig_d <= 0;elsestart_sig_d <= start_sig;assign start_sig_rising_vld = start_sig & (~start_sig_d);always @ (posedge CLK or negedge RSTn) //Asynchronous resetif (!RSTn)beginimk <= 18'b0;column_addr <= 10'b0;row_addr <= 10'b0;isCtrlDone <= 1'b0;endelse if (start_sig_rising_vld)beginimk <= 18'b1;column_addr <= 10'b1;row_addr <= 10'b1;isCtrlDone <= 1'b1;endelse if ( nxt_pix_sig )beginimk <= imk + 1'b1;row_addr <= imk / cols + 1;column_addr <= imk % cols + 1;isCtrlDone <= 1'b1;endelse isCtrlDone <= 1'b0;/*****************************************************************************************/assign row_addr_sig = row_addr;assign column_addr_sig = column_addr;assign pix_done_sig = isCtrlDone;/*****************************************************************************************/endmodule
win3by3_gen模块代码:
module win3by3_gen(CLK,RSTn,center_pix_sig,cols, // the column numbers of the input imagerows,rom_data_win, //input-from U1;column_addr_sig, //input-from U3; //output [9 : 0] addra;row_addr_sig, //input-from U3; //output [9 : 0] addra;rom_addr_sig, //output-to U1;data_out0, //output-to U4;data_out1,data_out2,data_out3,data_out4,data_out5,data_out6,data_out7,data_out8,win_data_done_sig //output-to U4/U3;complete the win data;);input CLK;input RSTn;input [7:0] rom_data_win;input [9:0] cols;input [9:0] rows;input center_pix_sig; //input [9:0] column_addr_sig;input [9:0] row_addr_sig;output [7:0] data_out0; //output-to U4;output [7:0] data_out1;output [7:0] data_out2;output [7:0] data_out3;output [7:0] data_out4;output [7:0] data_out5;output [7:0] data_out6;output [7:0] data_out7;output [7:0] data_out8;output [17:0] rom_addr_sig;output win_data_done_sig;/******************************************************************************************************************************/reg [9:0] m;always @ ( posedge CLK or negedge RSTn )if ( !RSTn )m <= 10'd1;else if ( center_pix_sig )m <= row_addr_sig[9:0];/******************************************************************************************************************************/reg [9:0] n;always @ ( posedge CLK or negedge RSTn )if ( !RSTn )n <= 10'd1;else if ( center_pix_sig )n <= column_addr_sig[9:0];/*****************************************************************************************************************************/reg [3:0] i;reg isWinDone;reg [17:0] rom_addr;reg [7:0] a11;reg [7:0] a12;reg [7:0] a13;reg [7:0] a21;reg [7:0] a22;reg [7:0] a23;reg [7:0] a31;reg [7:0] a32;reg [7:0] a33;/*****************************************************************************************************************************/reg get_9point_vld;always @ ( posedge CLK or negedge RSTn )if (!RSTn)get_9point_vld <= 1'b0;else if ( center_pix_sig )get_9point_vld <= 1'b1;else if ( i==4'd10 )get_9point_vld <= 1'b0;always @ ( posedge CLK or negedge RSTn )if ( !RSTn )isWinDone <= 1'b0;else if ( i==4'd10 )isWinDone <= 1'b1;elseisWinDone <= 1'b0;always @ ( posedge CLK or negedge RSTn )if ( !RSTn )i <= 4'd0;else if (i == 4'd10)i <= 4'd0;else if ( get_9point_vld )i <= i + 1'b1;always @ ( posedge CLK or negedge RSTn )if (!RSTn)rom_addr <= 0;else if ( get_9point_vld)case (i)4'd0:if(!(m==1 || n==1)) rom_addr <= (m-2)*cols + (n-1) -1;4'd1:if(!(m==1 )) rom_addr <= (m-2)*cols + n -1;4'd2:if(!(m==1 || n==cols)) rom_addr <= (m-2)*cols + (n+1) -1;4'd3:if(!(n==1)) rom_addr <= (m-1)*cols + (n-1) -1;4'd4:rom_addr <= (m-1)*cols + n -1;4'd5:if(!(n==cols)) rom_addr <= (m-1)*cols + (n+1) -1;4'd6:if(!(m==cols || n==1)) rom_addr <= m*cols + (n-1) -1;4'd7:if(!(m==cols)) rom_addr <= m*cols + n -1;4'd8:if(!(m==cols || n==cols)) rom_addr <= m*cols + (n+1) -1;default:;endcasealways @ ( posedge CLK or negedge RSTn )if (!RSTn)begina11 <= 0;a12 <= 0;a13 <= 0;a21 <= 0;a22 <= 0;a23 <= 0;a31 <= 0;a32 <= 0;a33 <= 0;endelse if ( get_9point_vld )case (i)4'd2:if ( m==1 || n==1 )a11 <= 0;elsea11 <= rom_data_win;4'd3:if ( m==1 ) a12 <= 0;else a12 <= rom_data_win;4'd4:if ( m==1 || n==cols ) a13 <= 0;else a13 <= rom_data_win;4'd5:if ( n==1 ) a21 <= 0;else a21 <= rom_data_win;4'd6:a22 <= rom_data_win;4'd7:if ( n==cols ) a23 <= 0;else a23 <= rom_data_win;4'd8:if ( m==cols || n==1 ) a31 <= 0;else a31 <= rom_data_win;4'd9:if ( m==cols ) a32 <= 0;else a32 <= rom_data_win;4'd10:if ( m==cols || n==cols ) a33 <= 0;else a33 <= rom_data_win;default:;endcase/**********************************************************************************************/assign win_data_done_sig = isWinDone;assign rom_addr_sig = rom_addr;assign data_out0 = a11;assign data_out1 = a12;assign data_out2 = a13;assign data_out3 = a21;assign data_out4 = a22;assign data_out5 = a23;assign data_out6 = a31;assign data_out7 = a32;assign data_out8 = a33;/**********************************************************************************************/endmodule
medfilter3by3模块代码:
module medfilter3by3(CLK,RSTn,win_data_sig, //input-from module of win3by3_gen;medfilt_done_sig, //output-to top;data_in0, //input-from module of win3by3_gen;data_in1,data_in2,data_in3,data_in4,data_in5,data_in6,data_in7,data_in8,medfilt_data_out //output-to top;);input CLK;input RSTn;input win_data_sig;input [7:0] data_in0; //output-to ;input [7:0] data_in1;input [7:0] data_in2;input [7:0] data_in3;input [7:0] data_in4;input [7:0] data_in5;input [7:0] data_in6;input [7:0] data_in7;input [7:0] data_in8;output medfilt_done_sig;output [7:0] medfilt_data_out;/******************************************************************************/reg [7:0] a11;reg [7:0] a12;reg [7:0] a13;reg [7:0] a21;reg [7:0] a22;reg [7:0] a23;reg [7:0] a31;reg [7:0] a32;reg [7:0] a33;reg [7:0] b11;reg [7:0] b12;reg [7:0] b13;reg [7:0] b21;reg [7:0] b22;reg [7:0] b23;reg [7:0] b31;reg [7:0] b32;reg [7:0] b33;reg [7:0] c11;reg [7:0] c12;reg [7:0] c13;reg [7:0] c21;reg [7:0] c22;reg [7:0] c23;reg [7:0] c31;reg [7:0] c32;reg [7:0] c33;reg [2:0] i;reg [7:0] medfilt_data;reg filt_done;reg cal_vld;always @ ( posedge CLK or negedge RSTn )if (!RSTn)begina11 <= 0;a12 <= 0;a13 <= 0;a21 <= 0;a22 <= 0;a23 <= 0;a31 <= 0;a32 <= 0;a33 <= 0;endelse if (win_data_sig)begina11 <= data_in0;a12 <= data_in1;a13 <= data_in2;a21 <= data_in3;a22 <= data_in4;a23 <= data_in5;a31 <= data_in6;a32 <= data_in7;a33 <= data_in8;endalways @ ( posedge CLK or negedge RSTn )if (!RSTn)i <= 3'd0;else if( cal_vld & ( i!=3 ) )i <= i + 1;elsei <= 0;always @ ( posedge CLK or negedge RSTn )if (!RSTn)cal_vld <= 1'b0;else if( win_data_sig )cal_vld <= 1'b1;else if( i==3'd3 )cal_vld <= 0;always @ ( posedge CLK or negedge RSTn )if (!RSTn)beginfilt_done <= 1'b0;b11 <= 0;b12 <= 0;b13 <= 0;b21 <= 0;b22 <= 0;b23 <= 0;b31 <= 0;b32 <= 0;b33 <= 0;c11 <= 0;c12 <= 0;c13 <= 0;c21 <= 0;c22 <= 0;c23 <= 0;c31 <= 0;c32 <= 0;c33 <= 0;medfilt_data <= 0;endelse if( cal_vld )case(i)3'd0:beginb11 <= max(a11, a21, a31);b12 <= max(a12, a22, a32);b13 <= max(a13, a23, a33);b21 <= med(a11, a21, a31);b22 <= med(a12, a22, a32);b23 <= med(a13, a23, a33);b31 <= min(a11, a21, a31);b32 <= min(a12, a22, a32);b33 <= min(a13, a23, a33);end3'd1:beginc31 <= max(b31, b32, b33);c22 <= med(b21, b22, b23);c13 <= min(b11, b12, b13);end3'd2:beginmedfilt_data <= med(c13, c22, c31);filt_done<=1'b1;end3'd3:filt_done <= 1'b0;default:;endcase/************************************************************************************/function [7:0] max;//if the data is signed number, please add the char signed behind key function;input [7:0] a, b, c;beginmax = (((a >= b) ? a : b) >= c ) ? ((a >= b) ? a : b) : c;endendfunctionfunction [7:0] med;input [7:0] a, b, c;beginmed = a < b ? (b < c ? b : a < c ? c : a) : (b > c ? b : a > c ? c : a);endendfunctionfunction [7:0] min;input [7:0] a, b, c;beginmin= (((a <= b) ? a : b) <= c ) ? ((a <= b) ? a : b) : c;endendfunction/************************************************************************************/assign medfilt_data_out = medfilt_data;assign medfilt_done_sig = filt_done;/**********************************************************************************/endmodule
仿真测试
仿真测试medfilter_tb模块代码:
module medfilter_tb;// Inputsreg CLK;reg RSTn;reg Start_sig;reg [18:0] pix_cnt; //512*512=262144=100,0000,0000,0000,0000// Outputswire Done_sig;wire [7:0] Data_out;integer fouti;// Instantiate the Unit Under Test (UUT)medfilter uut (.CLK(CLK),.RSTn(RSTn),.Start_sig(Start_sig),.Done_sig(Done_sig),.Data_out(Data_out));//assign Data_out = 0;//assign Done_sig = 0;initial begin// Initialize InputsCLK = 0;RSTn = 1;Start_sig = 0;fouti = $fopen("medfilter2_re.txt");// Wait 100 ns for global reset to finish#100; // To reset the system// Add stimulus hereRSTn = 0;Start_sig = 1;pix_cnt = 0;#100; // To start the system// Add stimulus hereRSTn = 1;pix_cnt = 1;endalways #10 CLK = ~CLK;always@(posedge CLK)beginif(Done_sig)pix_cnt <= pix_cnt + 1;endalways@(posedge CLK)beginif(pix_cnt == 19'd262145)beginStart_sig <= 0;$display("Image Medfilter Completed!n");$display("The all time is %d n",$time);$stop;endendalways@(posedge CLK)beginif(Done_sig)begin$fwrite(fouti, "%d", Data_out, "n");$display("%d",pix_cnt);endendendmodule
仿真图如下:
1112