FPGA study notes_image processing 3_FPGA implementation of median filter algorithm

FPGA study notes

Image processing algorithm

1. 中值滤波算法
   1.1 原理
   1.2 FPGA实现中值滤波算法

1. Median filtering algorithm

1.1 Principle
Set the gray value of each pixel to the median of the gray values ​​of all pixels in a certain area window of that point.
Features: Effectively suppress noise and protect image edge information. It is a classic noise-smoothing method and can be used to process RGB image formats.
Method:
Sort the data by size, and then find the median value according to the ordered sequence of numbers. Sorting algorithms: software algorithms such as bubble sorting, bipartite sorting, and so on. There are fewer sorting algorithms suitable for hardware.
3*3 image template

  • Sort the three rows of pixels separately
  • Respectively sort the 3 largest, 3 middle, and 3 smallest pixels in the three rows of pixels
  • Sort the largest smallest, middle middle, smallest largest to get the median

1.2 FPGA implementation of median filter algorithm

  • Project goal :
    Denoise the salt and pepper noise picture through the median filter algorithm, and display it on the TFT display through the FPGA.
    Insert picture description here

  • Project tools :
    ① Hardware: Intel Cyclone IV E series FPGA development board, 5-inch (800*480) TFT capacitive touch screen,
    ② Software: Quartus software, Picture2Hex software, MATLAB

  • Project component modules :
    ① pll: Generate the clock required for the project: 1. SDRAM controller clock; 2. SDRAM clock signal; 3. TFT screen controller clock
    ② uart serial port protocol (uart_rx, uart_tx)
    ③ read FIFO
    ④ write FIFO
    ⑤ SDRAM Control module
    ⑥ TFT screen control module
    ⑦ Median filter module

  • Verilog code

/*
1. 分别对三行像素进行排序
2. 分别对三行像素中:3个最大值,3个中间值,3个最小值,进行排序
3. 对:3最大值中的最小值,3个中间值中的中间值,3个最小值中的最大值,进行排序,得到中值
*/

module median_filter_r0(
		input							clk, //33MHZ
		input							rst_n,
		input			[15:0]			data_in, //灰度像素输入
		input							data_in_en,//lcd显示有效区使能信号
		
		input							hs_in,//行同步信号输入
		input							vs_in,//场同步信号输入
		
		output	wire	[15:0]			data_out,//中值处理后灰度像素输出
		output	wire	 				data_out_en,
		
		output	wire					hs_out,//行同步信号输出
		output	wire					vs_out//场同步信号输出
);
//----timing declaration----
	reg			hs_reg0;
	reg			hs_reg1;
	reg			hs_reg2;
				
	reg			vs_reg0;
	reg			vs_reg1;
	reg			vs_reg2;
				
	reg			de_reg0;
	reg			de_reg1;
	reg			de_reg2;
	
	
//----pipeline declaration----	
	wire [15:0] row0;
	wire [15:0] row1;
	wire [15:0] row2;
	
	reg  [15:0]	r0_c0;
	reg  [15:0]	r0_c1;
	reg  [15:0]	r0_c2;
	
	reg  [15:0]	r1_c0;
	reg  [15:0]	r1_c1;
	reg  [15:0]	r1_c2;
	
	reg  [15:0]	r2_c0;
	reg  [15:0]	r2_c1;
	reg  [15:0]	r2_c2;
	
	
	reg  [15:0]	r0_max;
	reg  [15:0]	r0_mid;
	reg  [15:0]	r0_min;

	reg  [15:0]	r1_max;
	reg  [15:0]	r1_mid;
	reg  [15:0]	r1_min;

	reg  [15:0]	r2_max;
	reg  [15:0]	r2_mid;
	reg  [15:0]	r2_min;
	
	
	reg  [15:0] max_max;
	reg  [15:0] max_mid;
	reg  [15:0] max_min;
	
	reg  [15:0] mid_max;
	reg  [15:0] mid_mid;
	reg  [15:0] mid_min;
	
	reg  [15:0] min_max;
	reg  [15:0] min_mid;
	reg  [15:0] min_min;
	
	reg  [15:0] mid;
	
//--------------------------------------------------
//----3行像素缓存--------------------------//
	shifter3_3 shifter3_3(
		.clken(data_in_en),
		.clock(clk),
		.shiftin(data_in),
		.shiftout(),
		.taps0x(row0),
		.taps1x(row1),
		.taps2x(row2)
	);
	
//----timing control-----------------------//
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			hs_reg0 <= 1'd0;
			hs_reg1 <= 1'd0;
			hs_reg2 <= 1'd0;
	
			vs_reg0 <= 1'd0;
			vs_reg1 <= 1'd0;
			vs_reg2 <= 1'd0;
	
			de_reg0 <= 1'd0;
			de_reg1 <= 1'd0;
			de_reg2 <= 1'd0;
		end
		else if(data_in_en)begin
			hs_reg0 <= hs_in;
			hs_reg1 <= hs_reg0;
			hs_reg2 <= hs_reg1;
	
			vs_reg0 <= vs_in;
			vs_reg1 <= vs_reg0;
			vs_reg2 <= vs_reg1;
	
			de_reg0 <= data_in_en;
			de_reg1 <= de_reg0;
			de_reg2 <= de_reg1;
		end
	end
//-----------------------------------------//

//----pipeline-----------------------------//
//----3*3 matix from image
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			r0_c0 <= 16'd0;
			r0_c1 <= 16'd0;
			r0_c2 <= 16'd0;

			r1_c0 <= 16'd0;
			r1_c1 <= 16'd0;
			r1_c2 <= 16'd0;

			r2_c0 <= 16'd0;
			r2_c1 <= 16'd0;
			r2_c2 <= 16'd0;			
	end 
	else if(data_in_en)begin
			r0_c0 <= row0;
			r0_c1 <= r0_c0;
			r0_c2 <= r0_c1;

			r1_c0 <= row1;
			r1_c1 <= r1_c0;
			r1_c2 <= r1_c1;

			r2_c0 <= row2;
			r2_c1 <= r2_c0;
			r2_c2 <= r2_c1;
	end
end
//------------------------------------------------------------------
//----1.分别对三行像素进行排序r0_max, r10_max,r2_max
//----r0------------------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			r0_max <= 16'd0;
			r0_mid <= 16'd0;
			r0_min <= 16'd0;		
		end 
		else if(data_in_en)begin
	
			if((r0_c0>=r0_c1)&&(r0_c0>=r0_c2))begin//r0_max <= r0_c0
				r0_max <= r0_c0;
				if(r0_c1>=r0_c2)begin
					r0_mid <= r0_c1;
					r0_min <= r0_c2;				
				end
				else begin
					r0_mid <= r0_c2;
					r0_min <= r0_c1;				
				end
			end
		
			else if((r0_c1>=r0_c0)&&(r0_c1>=r0_c2))begin//r0_max <= r0_c1;
				r0_max <= r0_c1;
				if(r0_c0>=r0_c2)begin
					r0_mid <= r0_c0;
					r0_min <= r0_c2;				
				end
				else begin
					r0_mid <= r0_c2;
					r0_min <= r0_c0;				
				end
			end
			
		else if((r0_c2>=r0_c0)&&(r0_c2>=r0_c1))begin//r0_max <= r0_c2;
				r0_max <= r0_c2;
				if(r0_c0>=r0_c1)begin
					r0_mid <= r0_c0;
					r0_min <= r0_c1;				
				end
				else begin
					r0_mid <= r0_c1;
					r0_min <= r0_c0;				
				end
		end
	end
	
end
//----r1--------------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			r1_max <= 16'd0;
			r1_mid <= 16'd0;
			r1_min <= 16'd0;			
	end 
	else if(data_in_en)begin
	
		if((r1_c0>=r1_c1)&&(r1_c0>=r1_c2))begin//r0_max <= r0_c0
			r1_max <= r1_c0;
			if(r1_c1>=r1_c2)begin
				r1_mid <= r1_c1;
				r1_min <= r1_c2;				
			end
			else begin
				r1_mid <= r1_c2;
				r1_min <= r1_c1;				
			end
		end
		
		else if((r1_c1>=r1_c0)&&(r1_c1>=r1_c2))begin//r0_max <= r0_c1;
			r1_max <= r1_c1;
			if(r1_c0>=r1_c2)begin
				r1_mid <= r1_c0;
				r1_min <= r1_c2;				
			end
			else begin
				r1_mid <= r1_c2;
				r1_min <= r1_c0;				
			end
		end
		
	else if((r1_c2>=r1_c0)&&(r1_c2>=r1_c1))begin//r0_max <= r0_c2;
			r1_max <= r1_c2;
			if(r1_c0>=r1_c1)begin
				r1_mid <= r1_c0;
				r1_min <= r1_c1;				
			end
			else begin
				r1_mid <= r1_c1;
				r1_min <= r1_c0;				
			end
		end
	end
	
end
//----r2--------------------------------------
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)begin
			r2_max <= 16'd0;
			r2_mid <= 16'd0;
			r2_min <= 16'd0;			
	end 
	else if(data_in_en)begin
	
		if((r2_c0>=r2_c1)&&(r2_c0>=r2_c2))begin//r0_max <= r0_c0
			r2_max <= r2_c0;
			if(r2_c1>=r2_c2)begin
				r2_mid <= r2_c1;
				r2_min <= r2_c2;				
			end
			else begin
				r2_mid <= r2_c2;
				r2_min <= r2_c1;				
			end
		end
		
		else if((r2_c1>=r2_c0)&&(r2_c1>=r2_c2))begin//r0_max <= r0_c1;
			r2_max <= r2_c1;
			if(r2_c0>=r2_c2)begin
				r2_mid <= r2_c0;
				r2_min <= r2_c2;				
			end
			else begin
				r2_mid <= r2_c2;
				r2_min <= r2_c0;				
			end
		end
		
	else if((r2_c2>=r2_c0)&&(r2_c2>=r2_c1))begin//r0_max <= r0_c2;
			r2_max <= r2_c2;
			if(r2_c0>=r2_c1)begin
				r2_mid <= r2_c0;
				r2_min <= r2_c1;				
			end
			else begin
				r2_mid <= r2_c1;
				r2_min <= r2_c0;				
			end
		end
	end
	
end
//--------------------------------------------------------------------
//----2. 分别对三行像素中:3个最大值,3个中间值,3个最小值,进行排序
//----3个最大值------------------------------------------------
	always@(posedge clk or negedge rst_n)begin
	
		if(!rst_n)begin
			max_max <= 16'd0;
			max_mid <= 16'd0;
			max_min <= 16'd0;			
		end
		else if(data_in_en)begin
			if((r0_max >= r1_max)&&(r0_max >= r2_max))begin//max_max <= r0_max
				max_max <= r0_max;
				if((r1_max >= r2_max))begin
					max_mid <= r1_max;
					max_min <= r2_max;						
				end 
				else begin
					max_mid <= r2_max;
					max_min <= r1_max;				
				end		
		end
		else if((r1_max >= r0_max)&&(r1_max >= r2_max))begin//max_max <= r1_max;
				max_max <= r1_max;
				if((r0_max >= r2_max))begin
					max_mid <= r0_max;
					max_min <= r2_max;						
				end 
				else begin
					max_mid <= r2_max;
					max_min <= r0_max;				
				end		
		end
		else if((r2_max >= r0_max)&&(r2_max >= r1_max))begin//max_max <= r2_max;
				max_max <= r2_max;
				if((r0_max >= r1_max))begin
					max_mid <= r0_max;
					max_min <= r1_max;						
				end 
				else begin
					max_mid <= r1_max;
					max_min <= r0_max;				
				end		
			end
		end
		
	end
//----3个中间值------------------------------------------------
	always@(posedge clk or negedge rst_n)begin
	
		if(!rst_n)begin
			mid_max <= 16'd0;
			mid_mid <= 16'd0;
			mid_min <= 16'd0;			
		end
		else if(data_in_en)begin
			if((r0_mid >= r1_mid)&&(r0_mid >= r2_mid))begin//mid_max <= r0_mid
				mid_max <= r0_mid;
				if((r1_mid >= r2_mid))begin
					mid_mid <= r1_mid;
					mid_min <= r2_mid;						
				end 
				else begin
					mid_mid <= r2_mid;
					mid_min <= r1_mid;				
				end		
		end
		else if((r1_mid >= r0_mid)&&(r1_mid >= r2_mid))begin//mid_max <= r1_mid;
				mid_max <= r1_mid;
				if((r0_mid >= r2_mid))begin
					mid_mid <= r0_mid;
					mid_min <= r2_mid;						
				end 
				else begin
					mid_mid <= r2_mid;
					mid_min <= r0_mid;				
				end		
		end
		else if((r2_mid >= r0_mid)&&(r2_mid >= r1_mid))begin//mid_max <= r2_mid;
				mid_max <= r2_mid;
				if((r0_mid >= r1_mid))begin
					mid_mid <= r0_mid;
					mid_min <= r1_mid;						
				end 
				else begin
					mid_mid <= r1_mid;
					mid_min <= r0_mid;				
				end		
			end
		end
		
	end

//----3个最小值------------------------------------------------
	always@(posedge clk or negedge rst_n)begin
	
		if(!rst_n)begin
			min_max <= 16'd0;
			min_mid <= 16'd0;
			min_min <= 16'd0;			
		end
		else if(data_in_en)begin
			if((r0_min >= r1_min)&&(r0_min >= r2_min))begin//min_max <= r0_min
				min_max <= r0_min;
				if((r1_min >= r2_min))begin
					min_mid <= r1_min;
					min_min <= r2_min;						
				end 
				else begin
					min_mid <= r2_min;
					min_min <= r1_min;				
				end		
		end
		else if((r1_min >= r0_min)&&(r1_min >= r2_min))begin//min_max <= r1_min;
				min_max <= r1_min;
				if((r0_min >= r2_min))begin
					min_mid <= r0_min;
					min_min <= r2_min;						
				end 
				else begin
					min_mid <= r2_min;
					min_min <= r0_min;				
				end		
		end
		else if((r2_min >= r0_min)&&(r2_min >= r1_min))begin//min_max <= r2_min;
				min_max <= r2_min;
				if((r0_min >= r1_min))begin
					min_mid <= r0_min;
					min_min <= r1_min;						
				end 
				else begin
					min_mid <= r1_min;
					min_min <= r0_min;				
				end		
			end
		end
		
	end
//---------------------------------------------------------------------------------
//----3. 对:3个最大值中的最小值,3个中间值中的中间值,3个最小值中的最大值,进行排序,得到中值
	always@(posedge clk or negedge rst_n)begin
	
		if(!rst_n)
			mid <= 16'd0;			
		else if(data_in_en)begin
			if(((max_min >= mid_mid)&&(max_min < min_max))||((max_min < mid_mid)&&(max_min >= min_max)) )//mid <= max_min;
				mid <= max_min;
			else if(((mid_mid >= max_min)&&(mid_mid < min_max))||((mid_mid < max_min)&&(mid_mid >= min_max)) )//mid <= mid_mid;
				mid <= mid_mid;
			else if(((min_max >= max_min)&&(min_max < mid_mid))||((min_max < max_min)&&(min_max >= mid_mid)) )//mid <= min_max;
				mid <= min_max;
			else;
		end		
		else;

	end
//----result-------------------------------------------------------------------------
	assign data_out = mid;
	assign data_out_en = de_reg2;
	assign hs_out = hs_reg2;
	assign vs_out = vs_reg2;
//-----------------------------------------------------------------------------------
endmodule


  • Project result
    5 inch TFT capacitive touch screen
    Image: 800*480 pixels
    (1). (Yiyanqianxi^^) Original network image:
    Insert picture description here
    (2). FPGA display original image:
    Insert picture description here
    (3). Add salt and pepper noise image:

  • Salt&pepper noise density=0.1
    Insert picture description here (4). FPGA median filter processing diagram:

  • Salt&pepper noise density=0.1
    Insert picture description here
    project result analysis:

  • Comparing Figure 3 and Figure 4, we can find that the median filter algorithm can effectively remove salt and pepper noise;


Reference materials: "FPGA System Design and Verification Practical Guide"
[Note]: Personal study notes, if there are mistakes, please feel free to enlighten me, this is polite~~~


Guess you like

Origin blog.csdn.net/weixin_50722839/article/details/113763837