文章目录

  • 前言
  • 一、中值滤波
  • 二、增加噪音
  • 三、Python实现中值滤波
  • 四、FPGA实现中值滤波
  • 总结



前言

  上一章讲了均值滤波,实现比较容易。今天我们开始中值滤波,难度升级。


一、中值滤波

  中值滤波的原理就是在以下3x3窗口里面选出9个像素的中值,一种方法是先选择使用排序算法,对9个像素排序,然后选出中值。另外一种方法是使用并行3步中值法,我们在Python以及FPGA中都采用3步中值法,方便实现。

FIR滤波器 中值滤波 心电信号 python 中值滤波python源码_最小值

二、增加噪音

  还是采用椒盐增噪。

img = plt.imread("lenna.png")
img = img * 255#图像是[0-1]--->[0-255]
img = img.astype(np.uint8)
prob = 0.92#生成盐噪生的概率为1-0.92=0.08
noise = np.random.choice((0, 255), size=img.shape, p=[prob, 1 - prob])#产生和图像维度一样的噪音矩阵
noise_img = np.where(noise == 0, img, 255).astype(np.uint8)#生成噪音图像,椒(0黑色)盐噪声的盐(255白色)
plt.imsave("noise.png", noise_img)#保存噪音图像,用于FPGA去噪
fig = plt.figure(figsize=(10, 6))
ax = plt.subplot(1, 2, 1)
ax.set_title("raw image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(img)
ax = plt.subplot(1, 2, 2)
ax.set_title("salt image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(noise_img)

FIR滤波器 中值滤波 心电信号 python 中值滤波python源码_fpga开发_02

三、Python实现中值滤波

def image_gray(image):
    gray = np.dot(image[:, :, ...], [0.299, 0.587, 0.114])#等同0.299 * image[:, :, 0] + 0.587 * image[:, :, 1] + 0.114 * image[:, :, 2]
    return gray.astype(np.uint8)
    
def median_filter(image, n):
    h, w = image.shape
    filtered_image = np.zeros((h, w))
    m = int((n - 1) / 2)
    for i in range(m, h - m):
        for j in range(m, w - m):
            kernel = image[i - m: i + m + 1, j - m: j + m + 1] 
            max1, max2, max3 = np.max(kernel[0, :]), np.max(kernel[1, :]), np.max(kernel[2, :])#每一行的最大值
            mid1, mid2, mid3 = np.median(kernel[0, :]), np.median(kernel[1, :]), np.median(kernel[2, :])#每一行的中值
            min1, min2, min3 = np.min(kernel[0, :]), np.min(kernel[1, :]), np.min(kernel[2, :])#每一行的最小值
            max_min = np.min([max1, max2, max3])#最大值中选出最小值
            mid_mid = np.median([mid1, mid2, mid3])#中值中选出中值
            min_max = np.max([min1, min2, min3])#最小值中选出最大值
            filtered_image[i, j] = np.median([max_min, mid_mid, min_max])#从三者选出最后的中值
    return filtered_image.astype(np.uint8)
    
noise_gray = image_gray(noise_img)
median_img = median_filter(noise_gray, 3)
fig = plt.figure(figsize=(10, 6))
ax = plt.subplot(1, 2, 1)
ax.set_title("raw image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(noise_gray, cmap="gray")
ax = plt.subplot(1, 2, 2)
ax.set_title("salt image")
ax.set_xlabel("width")
ax.set_ylabel("height")
plt.imshow(median_img, cmap="gray")

FIR滤波器 中值滤波 心电信号 python 中值滤波python源码_python_03

  可以看到,中值滤波实现的效果要比均值滤波要好。可以移步至《Python与FPGA——均值滤波》教程一探究竟。


四、FPGA实现中值滤波

module  ycbcr_to_mf
(
	input	wire			vga_clk		,//vga时钟
	input	wire			sys_rst_n	,//复位信号
	input	wire	[7:0]	y_data		,//灰度处理的图像像素
	input	wire			rgb_valid	,//vga显示有效区域
	
	output	wire	[15:0]	mf_data	//中值像素
);

//shift ram
wire	[7:0]	data_row1	;
wire	[7:0]	data_row2	;
wire	[7:0]	data_row3	;
//3*3像素数据
reg		[7:0]	p11			;
reg		[7:0]	p12			;
reg		[7:0]	p13			;
reg		[7:0]	p21			;
reg		[7:0]	p22			;
reg		[7:0]	p23			;
reg		[7:0]	p31			;
reg		[7:0]	p32			;
reg		[7:0]	p33			;
//第一行最大值、最小值、中值
wire	[7:0]	data_max_1	;
wire	[7:0]	data_min_1	;
wire	[7:0]	data_med_1	;
//第二行最大值、最小值、中值
wire	[7:0]	data_max_2	;
wire	[7:0]	data_min_2	;
wire	[7:0]	data_med_2	;
//第三行最大值、最小值、中值
wire	[7:0]	data_max_3	;
wire	[7:0]	data_min_3	;
wire	[7:0]	data_med_3	;
//最小值的最大值
wire	[7:0]	data_min_to_max	;
//最大值的最小值
wire	[7:0]	data_max_to_min	;
//中值的中值
wire	[7:0]	data_med_to_med	;
//最大值、最小值、中值
wire	[7:0]	data_max	;
wire	[7:0]	data_min	;
wire	[7:0]	data_med	;
//Y值有效信号
reg				y_valid		;

assign  data_row3 = y_data  ;
//中值拼接565
assign  mf_data = {data_med[7:3],data_med[7:2],data_med[7:3]}  ;

always@(posedge vga_clk or negedge sys_rst_n)	
	if(sys_rst_n == 1'b0)
		y_valid  <=  1'b0  ;
	else
		y_valid  <=  rgb_valid  ;

always@(posedge vga_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		begin
			{p11,p12,p13}  <=  24'd0  ;
			{p21,p22,p23}  <=  24'd0  ;
			{p31,p32,p33}  <=  24'd0  ;
		end
	else  if(y_valid == 1'b1)
		begin
			{p11,p12,p13}  <= {p12,p13,data_row1}  ;
			{p21,p22,p23}  <= {p22,p23,data_row2}  ;
			{p31,p32,p33}  <= {p32,p33,data_row3}  ;
		end	
	else
		begin
			{p11,p12,p13}  <=  24'd0  ;
			{p21,p22,p23}  <=  24'd0  ;
			{p31,p32,p33}  <=  24'd0  ;
		end	
//移位寄存器
shift_ram_gen  shift_ram_gen_inst
(
	.clock 		(vga_clk	),
	.shiftin	(data_row3	),
	.shiftout 	(			),
	.taps0x 	(data_row2	),
	.taps1x 	(data_row1	)
);
//比较出三个像素最大,最小,中值
data_compare  data_compare_1
(
	.a	(p11		),
	.b	(p12		),
	.c	(p13		),
	.max(data_max_1	),
	.min(data_min_1	),
	.med(data_med_1	)
);
//比较出三个像素最大,最小,中值
data_compare  data_compare_2
(
	.a	(p21		),
	.b	(p22		),
	.c	(p23		),
	.max(data_max_2	),
	.min(data_min_2	),
	.med(data_med_2	)
);
//比较出三个像素最大,最小,中值
data_compare  data_compare_3
(
	.a	(p31		),
	.b	(p32		),
	.c	(p33		),
	.max(data_max_3	),
	.min(data_min_3	),
	.med(data_med_3	)
);
//最小值选出最大值
data_compare  data_compare_min_to_max
(
	.a	(data_min_1		),
	.b	(data_min_2		),
	.c	(data_min_3		),
	.max(data_min_to_max),
	.min(),
	.med()
);
//最大值选出最小值
data_compare  data_compare_max_to_min
(
	.a	(data_max_1		),
	.b	(data_max_2		),
	.c	(data_max_3		),
	.max(),
	.min(data_max_to_min),
	.med()
);
//中值选出中值
data_compare  data_compare_med_to_med
(
	.a	(data_med_1		),
	.b	(data_med_2		),
	.c	(data_med_3		),
	.max(),
	.min(),
	.med(data_med_to_med)
);
//最后,将最大,最小,中值选出中值
data_compare  data_compare_inst
(
	.a	(data_min_to_max),
	.b	(data_max_to_min),
	.c	(data_med_to_med),
	.max(data_max		),
	.min(data_min		),
	.med(data_med		)
);

endmodule

  比较模块。

module  data_compare
(
	input	wire	[7:0]	a			,
	input	wire	[7:0]	b			,
	input	wire	[7:0]	c			,
			
	output	reg		[7:0]	max			,
	output	reg		[7:0]	min			,
	output	reg		[7:0]	med	
);
//三者比较选最大值
always@(*)
	if((a >= b)&&(a >= c))
		max  =  a  ;
	else  if((b >= a)&&(b >= c))
		max  =  b  ;
	else  if((c >= a)&&(c >= b))
		max  =  c  ;
	else
		max  =  8'd0  ;
//三者比较选最小值	
always@(*)
	if((a <= b)&&(a <= c))
		min  =  a  ;
	else  if((b <= a)&&(b <= c))
		min  =  b  ;
	else  if((c <= a)&&(c <= b))
		min  =  c  ;
	else
		min  =  8'd0  ;
//三者比较选中值	
always@(*)
	if(((a >= b)&&(a <= c))||((a <= b)&&(a >= c)))
		med  =  a  ;
	else  if(((b >= a)&&(b <= c))||((b <= a)&&(b >= c)))
		med  =  b  ;
	else  if(((c >= a)&&(c <= b))||((c <= a)&&(c >= b)))
		med  =  c  ;
	else
		med  =  8'd0  ;

endmodule

  采集卡采集到的原图。

FIR滤波器 中值滤波 心电信号 python 中值滤波python源码_开发语言_04


  采集卡采集到的中值滤波图像。

FIR滤波器 中值滤波 心电信号 python 中值滤波python源码_最小值_05


  移位寄存器是调用的IP,所以就不过多介绍。再课程的最后,会对移位寄存器进行讨论。

总结

  从结果来看,不管是Python实现中值滤波,还是FPGA实现中值滤波,实现的效果都比均值滤波效果好。至于选择Python还是选择FPGA,对于一个公司而言,就会考虑成本,性能,用户群体等众多因素,而不是简简单单的方便(Python),还有简简单单的快(FPGA)。