文章目录
- 前言
- 一、中值滤波
- 二、增加噪音
- 三、Python实现中值滤波
- 四、FPGA实现中值滤波
- 总结
前言
上一章讲了均值滤波,实现比较容易。今天我们开始中值滤波,难度升级。
一、中值滤波
中值滤波的原理就是在以下3x3窗口里面选出9个像素的中值,一种方法是先选择使用排序算法,对9个像素排序,然后选出中值。另外一种方法是使用并行3步中值法,我们在Python以及FPGA中都采用3步中值法,方便实现。
二、增加噪音
还是采用椒盐增噪。
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)
三、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")
可以看到,中值滤波实现的效果要比均值滤波要好。可以移步至《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
采集卡采集到的原图。
采集卡采集到的中值滤波图像。
移位寄存器是调用的IP,所以就不过多介绍。再课程的最后,会对移位寄存器进行讨论。
总结
从结果来看,不管是Python实现中值滤波,还是FPGA实现中值滤波,实现的效果都比均值滤波效果好。至于选择Python还是选择FPGA,对于一个公司而言,就会考虑成本,性能,用户群体等众多因素,而不是简简单单的方便(Python),还有简简单单的快(FPGA)。