大俠好,歡迎來到FPGA技術(shù)江湖,江湖偌大,相見即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。
今天給大俠帶來基于FPGA的中值濾波器設(shè)計(jì),附源碼,獲取源碼,請(qǐng)?jiān)凇癋PGA技術(shù)江湖”公眾號(hào)內(nèi)回復(fù)“中值濾波器設(shè)計(jì)源碼”,可獲取源碼文件。話不多說,上貨。
設(shè)計(jì)背景
在圖像采集、轉(zhuǎn)換和傳輸?shù)倪^程中,由于成像系統(tǒng)、傳輸介質(zhì)和工作環(huán)境等固有的缺陷,不可避免地產(chǎn)生各種類型的噪聲,導(dǎo)致獲取的圖像往往與實(shí)際圖像有差異。圖像質(zhì)量的下降使得圖像后續(xù)處理(如邊緣檢測、圖像分割、特征提取、模式識(shí)別等)產(chǎn)生困難,因此對(duì)噪聲圖像進(jìn)行濾波是必要預(yù)處理過程,這可以使處理后的圖像更適合觀察或提取有用信息。但濾波算法在去除噪聲的同時(shí)難免對(duì)圖像造成一定程度的模糊,造成細(xì)節(jié)信息的丟失。中值濾波是對(duì)圖像的低通濾波,可有效濾除高頻噪聲,增強(qiáng)圖像清晰度。
設(shè)計(jì)原理
中值濾波是對(duì)一個(gè)滑動(dòng)窗口內(nèi)的諸像素灰度值排序,用其中值代替窗口中心象素的原來灰度值,它是一種非線性的圖像平滑法,它對(duì)脈沖干擾級(jí)椒鹽噪聲(脈沖噪聲)的抑制效果好,在抑制隨機(jī)噪聲的同時(shí)能有效保護(hù)邊緣少受模糊。
本設(shè)計(jì)采用3*3的滑動(dòng)窗口,先將3*3窗口中每一列數(shù)據(jù)進(jìn)行從大到小的排序,列排序后,再對(duì)窗口中每一行的數(shù)據(jù)從大到小進(jìn)行排序,之后再對(duì)窗口中對(duì)角線上的數(shù)據(jù)進(jìn)行排序,得到中間值,即為9個(gè)數(shù)的中值。其示意圖如下:
這種濾波算法,極大減少了比較的次數(shù),提高了圖像處理的速度,在FPGA上,不僅易于實(shí)現(xiàn),而且占用了更少的片上資源。
這種濾波算法,極大減少了比較的次數(shù),提高了圖像處理的速度,在FPGA上,不僅易于實(shí)現(xiàn),而且占用了更少的片上資源。
設(shè)計(jì)架構(gòu)圖
本設(shè)計(jì)可分為四個(gè)模塊,分別是:ROM模塊,用于存儲(chǔ)處理圖像的信息;3*3窗口生成模塊,用于生成濾波的滑動(dòng)窗口,得到窗口內(nèi)的所有元素?cái)?shù)據(jù);計(jì)數(shù)器控制模塊,主要用于獲得中心像素點(diǎn)的地址信息;3*3中值濾波模塊,主要用于得到某一中心像素點(diǎn)的3*3滑動(dòng)窗口區(qū)域的灰度值的中值,作為中心像素點(diǎn)的值。
設(shè)計(jì)代碼
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設(shè)計(jì)模塊代碼:
// synopsys translate_off `timescale 1 ps / 1 ps // synopsys translate_on module rom_512by512 ( address, clock, q); input [17:0] address; input clock; output [7:0] q; `ifndef ALTERA_RESERVED_QIS // synopsys translate_off `endif tri1 clock; `ifndef ALTERA_RESERVED_QIS // synopsys translate_on `endif wire [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)); defparam altsyncram_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 top nxt_pix_sig, //input-from --start next center point pixel cols, column_addr_sig, //output row_addr_sig, //output-to pix_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 image reg [9:0] row_addr; // The row of the centeral pixel reg [9:0] column_addr; // The column of the centeral pixel reg start_sig_d; wire start_sig_rising_vld; always @ (posedge CLK or negedge RSTn) //Asynchronous reset if (!RSTn) start_sig_d <= 0; else start_sig_d <= start_sig; assign start_sig_rising_vld = start_sig & (~start_sig_d); always @ (posedge CLK or negedge RSTn) //Asynchronous reset if (!RSTn) begin imk <= 18'b0; column_addr <= 10'b0; row_addr <= 10'b0; isCtrlDone <= 1'b0; end else if (start_sig_rising_vld) begin imk <= 18'b1; column_addr <= 10'b1; row_addr <= 10'b1; isCtrlDone <= 1'b1; end else if ( nxt_pix_sig ) begin imk <= imk + 1'b1; row_addr <= imk / cols + 1; column_addr <= imk % cols + 1; isCtrlDone <= 1'b1; end else 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 image rows, 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; else isWinDone <= 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:; endcase always @ ( posedge CLK or negedge RSTn ) if (!RSTn) begin a11 <= 0; a12 <= 0; a13 <= 0; a21 <= 0; a22 <= 0; a23 <= 0; a31 <= 0; a32 <= 0; a33 <= 0; end else if ( get_9point_vld ) case (i) 4'd2: if ( m==1 || n==1 ) a11 <= 0; else a11 <= 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) begin a11 <= 0; a12 <= 0; a13 <= 0; a21 <= 0; a22 <= 0; a23 <= 0; a31 <= 0; a32 <= 0; a33 <= 0; end else if (win_data_sig) begin a11 <= 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; end always @ ( posedge CLK or negedge RSTn ) if (!RSTn) i <= 3'd0; else if( cal_vld & ( i!=3 ) ) i <= i + 1; else i <= 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) begin filt_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; end else if( cal_vld ) case(i) 3'd0: begin b11 <= 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); end 3'd1: begin c31 <= max(b31, b32, b33); c22 <= med(b21, b22, b23); c13 <= min(b11, b12, b13); end 3'd2: begin medfilt_data <= med(c13, c22, c31); filt_done<=1'b1; end 3'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; begin max = (((a >= b) ? a : b) >= c ) ? ((a >= b) ? a : b) : c; end endfunction function [7:0] med; input [7:0] a, b, c; begin med = a < b ? (b < c ? b : a < c ? c : a) : (b > c ? b : a > c ? c : a); end endfunction function [7:0] min; input [7:0] a, b, c; begin min= (((a <= b) ? a : b) <= c ) ? ((a <= b) ? a : b) : c; end endfunction /************************************************************************************/ assign medfilt_data_out = medfilt_data; assign medfilt_done_sig = filt_done; /**********************************************************************************/ endmodule
仿真測試
仿真測試medfilter_tb模塊代碼:
module medfilter_tb; // Inputs reg CLK; reg RSTn; reg Start_sig; reg [18:0] pix_cnt; //512*512=262144=100,0000,0000,0000,0000 // Outputs wire 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 Inputs CLK = 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 here RSTn = 0; Start_sig = 1; pix_cnt = 0; #100; // To start the system // Add stimulus here RSTn = 1; pix_cnt = 1; end always #10 CLK = ~CLK; always@(posedge CLK) begin if(Done_sig) pix_cnt <= pix_cnt + 1; end always@(posedge CLK) begin if(pix_cnt == 19'd262145) begin Start_sig <= 0; $display("Image Medfilter Completed! "); $display("The all time is %d ",$time); $stop; end end always@(posedge CLK) begin if(Done_sig) begin $fwrite(fouti, "%d", Data_out, " "); $display("%d",pix_cnt); end end endmodule
仿真圖如下:
-
FPGA
+關(guān)注
關(guān)注
1629文章
21736瀏覽量
603248 -
圖像采集
+關(guān)注
關(guān)注
2文章
300瀏覽量
41280 -
濾波器
+關(guān)注
關(guān)注
161文章
7811瀏覽量
178088 -
濾波算法
+關(guān)注
關(guān)注
2文章
89瀏覽量
13723
原文標(biāo)題:源碼系列:基于FPGA的中值濾波器設(shè)計(jì)(附源碼)
文章出處:【微信號(hào):HXSLH1010101010,微信公眾號(hào):FPGA技術(shù)江湖】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論