FPGA学习笔记_图像处理3_FPGA实现中值滤波算法

FPGA学习笔记

图像处理算法

1. 中值滤波算法
   1.1 原理
   1.2 FPGA实现中值滤波算法
2. 应用MATLAB给图片加椒盐噪声
3. 项目结果

1. 中值滤波算法

1.1 原理

  • 将每一像素点的灰度值设置为该点的某领域窗口内的所有像素点灰度值的中值。
  • 特点:有效抑制噪声,保护图像边缘信息,是经典的平滑噪声方法,可用作处理RGB图像格式。

方法:

将数据按大小排序,然后根据有序的数字序列找中值,排序算法:冒泡排序,二等分排序等软件算法,适合硬件的排序算法比较少。
3*3图像模板

  • 分别对三行像素进行排序
  • 分别对三行像素中的3个最大,3个中间,3个最小分别进行排序
  • 对最大的最小,中间的中间,最小的最大进行排序得到中值

1.2 FPGA实现中值滤波算法

  • 项目目标
    将椒盐噪声图片,通过中值滤波算法,进行去噪处理,并通过FPGA显示到TFT显示屏上。
    在这里插入图片描述

  • 项目工具
    ① 硬件:Intel Cyclone IV E系列FPGA开发板,5寸(800*480)TFT电容触摸显示屏;
    ② 软件:Quartus软件,Picture2Hex软件,MATLAB;

  • 项目组成模块
    ① pll: 产生项目所需时钟:1. SDRAM控制器时钟;2. SDRAM时钟信号;3. TFT屏控制器时钟
    ② uart串口协议(uart_rx, uart_tx)
    ③ 读FIFO
    ④ 写FIFO
    ⑤ SDRAM控制模块
    ⑥ TFT屏控制模块
    ⑦ 中值滤波模块

  • Verilog代码

/*
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



2. 应用MATLAB给图片加椒盐噪声

  • MATLAB代码
close all;clear all;clc;%清除

L = imread('C:\Users\GloriaHuo\Desktop\0001.jpg');  % 在指定路径读取图像
J = imnoise(L,'salt & pepper', 0.1); %Salt&pepper 噪声密度=0.1

figure(1);
imshow(L);  % 显示原图
figure(2);
imshow(J); %立即弹出窗口,显示加了加椒盐噪声后的图片
hold on;

imwrite(J,'C:\Users\GloriaHuo\Desktop\0001_saltpepper.jpg');%把加入噪声的图像保存起来


  • 1. 原图像
    在这里插入图片描述
  • 2. 加入椒盐噪声图像
    在这里插入图片描述

3. 项目结果

5寸TFT电容触摸显示屏
图像:800*480像素

(1). (易烊千玺^^)网络原图:
在这里插入图片描述
(2). FPGA显示原图:
在这里插入图片描述
(3). 加入椒盐噪声图:

  • Salt&pepper 噪声密度=0.1
    在这里插入图片描述
    (4). FPGA中值滤波处理图:

  • Salt&pepper 噪声密度=0.1
    在这里插入图片描述
    项目结果分析:

  • 对比图3与图4可以发现,中值滤波算法可以有效地去除椒盐噪声;


参考资料:《FPGA系统设计与验证实战指南》
【注】:个人学习笔记,如有错误,望不吝赐教,这厢有礼了~~~


  • 8
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值