一、中值滤波理论
中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值.
中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近真实值,从而消除孤立的噪声点。
二、MATLAB实现
clc; %清除命令窗口的内容
clear all; %清除工作空间的所有变量,函数,和MEX文件
close all; %关闭所有的Figure窗口
RGB = imread('C:\Users\47199\Desktop\是.png'); %读取图片
imgn = imnoise(RGB,'salt & pepper',0.05); %椒盐密度0.05
%g=imnoise(f,‘salt & pepper’,d)用椒盐噪声污染图像f,其中d是噪声密度(即包括噪声值的图像区域的百分比)。
%因此,大约有d*numel(f)个像素受到影响。默认的噪声密度为0.05。
gray = im2double(rgb2gray(imgn)); %灰度图im2double将图像 I 转换为双精度。 rgb2gray将真彩色图像RGB转换为灰度强度图像I
[ROW,COL, DIM] = size(gray); %得到图像行列数
%--------------------------------------------------------------------------
% Mean Filter 均值滤波
%--------------------------------------------------------------------------
Mean_Img = zeros(ROW,COL); %生成一个大小为行列的0矩阵
for r = 2:1:ROW-1
for c = 2:1:COL-1
Mean_Img(r,c) = (gray(r-1, c-1) + gray(r-1, c) + gray(r-1, c+1) + gray(r, c-1) + gray(r, c) + gray(r, c+1) + gray(r+1, c-1) + gray(r+1, c) + gray(r+1, c+1)) / 9;
end %求均值
end
%--------------------------------------------------------------------------
% Median Filter 中值滤波
%--------------------------------------------------------------------------
Median_Img = zeros(ROW,COL);
for r = 2:ROW-1 %不从1开始,是因为最小值为r-1
for c = 2:COL-1
median3x3 =[gray(r-1,c-1) gray(r-1,c) gray(r-1,c+1)
gray(r,c-1) gray(r,c) gray(r,c+1)
gray(r+1,c-1) gray(r+1,c) gray(r+1,c+1)];
sort1 = sort(median3x3, 2, 'descend'); %Y=sort(X,DIM,MODE),DIM表示对哪一个维数进行排序
%例如当X是一个二维矩阵,当DIM=1时表示对X的每一列进行排序,当DIM=2时表示对X的每一行进行排序
%参数MODE表示按哪一种模式进行排序,当MODE=‘ASCEND’的时进行升序排序,当MODE=‘DESCEND’时,进行降序排序。
sort2 = sort([sort1(1), sort1(4), sort1(7)], 'descend');
sort3 = sort([sort1(2), sort1(5), sort1(8)], 'descend');
sort4 = sort([sort1(3), sort1(6), sort1(9)], 'descend');
mid_num = sort([sort2(3), sort3(2), sort4(1)], 'descend');
Median_Img(r,c) = mid_num(2);
end
end
gray2 = im2double(Median_Img);
Median2_Img = zeros(ROW,COL);
for r = 2:ROW-1 %不从1开始,是因为最小值为r-1
for c = 2:COL-1
median3x32 =[gray2(r-1,c-1) gray2(r-1,c) gray2(r-1,c+1)
gray2(r,c-1) gray2(r,c) gray2(r,c+1)
gray2(r+1,c-1) gray2(r+1,c) gray2(r+1,c+1)];
sort5 = sort(median3x32, 2, 'descend'); %Y=sort(X,DIM,MODE),DIM表示对哪一个维数进行排序
%例如当X是一个二维矩阵,当DIM=1时表示对X的每一列进行排序,当DIM=2时表示对X的每一行进行排序
%参数MODE表示按哪一种模式进行排序,当MODE=‘ASCEND’的时进行升序排序,当MODE=‘DESCEND’时,进行降序排序。
sort6 = sort([sort5(1), sort5(4), sort5(7)], 'descend');
sort7 = sort([sort5(2), sort5(5), sort5(8)], 'descend');
sort8 = sort([sort5(3), sort5(6), sort5(9)], 'descend');
mid_num2 = sort([sort6(3), sort7(2), sort8(1)], 'descend');
Median2_Img(r,c) = mid_num2(2);
end
end
gray3 = im2double(Mean_Img);
Median3_Img = zeros(ROW,COL);
for r = 2:ROW-1 %不从1开始,是因为最小值为r-1
for c = 2:COL-1
median3x33 =[gray3(r-1,c-1) gray3(r-1,c) gray3(r-1,c+1)
gray3(r,c-1) gray3(r,c) gray3(r,c+1)
gray3(r+1,c-1) gray3(r+1,c) gray3(r+1,c+1)];
sort9 = sort(median3x33, 2, 'descend'); %Y=sort(X,DIM,MODE),DIM表示对哪一个维数进行排序
%例如当X是一个二维矩阵,当DIM=1时表示对X的每一列进行排序,当DIM=2时表示对X的每一行进行排序
%参数MODE表示按哪一种模式进行排序,当MODE=‘ASCEND’的时进行升序排序,当MODE=‘DESCEND’时,进行降序排序。
sort10 = sort([sort9(1), sort9(4), sort9(7)], 'descend');
sort11 = sort([sort9(2), sort9(5), sort9(8)], 'descend');
sort12 = sort([sort9(3), sort9(6), sort9(9)], 'descend');
mid_num3 = sort([sort10(3), sort11(2), sort12(1)], 'descend');
Median3_Img(r,c) = mid_num3(2);
end
end
%--------------------------------------------------------------------------
% Show Image
%--------------------------------------------------------------------------
subplot(1,1,1); imshow(imgn); title('椒盐噪声');
% subplot(2,3,2); imshow(gray); title('灰度图');
% subplot(2,3,3); imshow(Mean_Img); title('均值滤波');
% subplot(2,3,4); imshow(Median_Img); title('中值滤波');
% subplot(2,3,5); imshow(Median2_Img); title('二次中值滤波');
% subplot(2,3,6); imshow(Median3_Img); title('均值滤波后中值滤波');
% 由实验可知:
% 1、椒盐噪声就是黑白噪声,均值滤波对椒盐噪声基本无作用。
% 2、中值滤波对椒盐噪声的处理非常好。
效果图
三、FPGA实现
1.FPGA实现矩阵运算
图像处理最常见的运算是矩阵,讨论两种矩阵的实现方法:
(1)shift IP核
altera提供了矩阵的IP核,可以设置位宽8、两路输出、每行480个深度(图像长度),配置如图:
对此IP核进行仿真:
由仿真看到输出延时三个时钟clk
(2)双fifo法
借鉴咸鱼老哥的图:
assign wr_en_1 = (cnt_row < 4) ? din_vld : 1'b0; //不写最后1行
assign rd_en_1 = (cnt_row > 0) ? din_vld : 1'b0; //从第1行开始读
assign wr_en_2 = (cnt_row < 3) ? din_vld : 1'b0; //不写最后2行
assign rd_en_2 = (cnt_row > 1) ? din_vld : 1'b0; //从第2行开始读
fifo设置为show_ahead模式,提前读数,延时一个周期,且可在转行时以第一列数据进行填充。
对输入数据,第一个fifo输出数据,第二个fifo输出数据打拍,形成3*3矩阵,且进行滑动:
//打拍形成矩阵数据 延时一个clk
always@(posedge clk or negedge rst_n)
begin
if(!rst_n) begin
{matrix_11, matrix_12, matrix_13} <= {8'd0, 8'd0, 8'd0};
{matrix_21, matrix_22, matrix_23} <= {8'd0, 8'd0, 8'd0};
{matrix_31, matrix_32, matrix_33} <= {8'd0, 8'd0, 8'd0};
end
else begin
{matrix_11, matrix_12, matrix_13} <= {matrix_12, matrix_13, row_1};
{matrix_21, matrix_22, matrix_23} <= {matrix_22, matrix_23, row_2};
{matrix_31, matrix_32, matrix_33} <= {matrix_32, matrix_33, row_3};
end
end
由于此时数据输出的前后顺序是相反的,改变下定义,看起来方便
//矩阵数据选取 无延时
assign row_1 = fifo2;
assign row_2 = fifo1;
assign row_3 = Y_in;
对此方法的3*3矩阵进行仿真:
initial begin
din_vld = 0;
din = 0;
#(`Clock*20+2);
//--------------------------------------------------- 1-10
din_vld = 1;
din = 1;
#(`Clock);
din = 2;
#(`Clock);
din = 3;
#(`Clock);
din = 4;
#(`Clock);
din = 5;
#(`Clock);
din = 6;
#(`Clock);
din = 7;
#(`Clock);
din = 8;
#(`Clock);
din = 9;
#(`Clock);
din = 10;
#(`Clock);
din_vld = 0;
#(`Clock*5);
......
2.排序
定义sort函数,排大小
module sort(
clk,
rst_n,
data0,
data1,
data2,
max_data, //最大值
mid_data, //中间值
min_data //最小值
);
input clk;
input rst_n;
input data0;
input data1;
input data2;
output max_data;
output mid_data;
output min_data;
wire clk;
wire rst_n;
wire [7:0] data0;
wire [7:0] data1;
wire [7:0] data2;
reg [7:0] max_data;
reg [7:0] mid_data;
reg [7:0] min_data;
//Max_Data
//-------------------------------------------------------------------------------------
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
Max_Data <= 'd0;
else if(Data1 >= Data2 && Data1 >= Data3)
Max_Data <= Data1;
else if(Data2 >= Data1 && Data2 >= Data3)
Max_Data <= Data2;
else if(Data3 >= Data1 && Data3 >= Data2)
Max_Data <= Data3;
end
//-------------------------------------------------------------------------------------
//Mid_Data
//-------------------------------------------------------------------------------------
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
Mid_Data <= 'd0;
else if((Data2 >= Data1 && Data1 >= Data3) || (Data3 >= Data1 && Data1 >= Data2))
Mid_Data <= Data1;
else if((Data1 >= Data2 && Data2 >= Data3) || (Data3 >= Data2 && Data2 >= Data1))
Mid_Data <= Data2;
else if((Data1 >= Data3 && Data3 >= Data2) || (Data2 >= Data3 && Data3 >= Data1))
Mid_Data <= Data3;
end
//-------------------------------------------------------------------------------------
//Min_Data
//-------------------------------------------------------------------------------------
always @(posedge Clk or negedge Rst_n)
begin
if(!Rst_n)
Min_Data <= 'd0;
else if(Data3 >= Data1 && Data2 >= Data1)
Min_Data <= Data1;
else if(Data3 >= Data2 && Data1 >= Data2)
Min_Data <= Data2;
else if(Data1 >= Data3 && Data2 >= Data3)
Min_Data <= Data3;
end
然后三行的最小值取最大值,三行的中间值取中间值,三行的最大值取最小值,将前面的这三个值再取取中间值----最终的中值,这个操作对于信号来说延时了3个clk,结构图:
3.中值滤波是在上一个Ycbcr提取到Y分量的基础上做的(当然也可以直接对tft输出滤波)。
4.控制信号在上面的操作中,共有4个clk的时延
//信号同步
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
median_de_r <= 4'b0;
median_hs_r <= 4'b0;
median_vs_r <= 4'b0;
median_pwm_r <= 4'b0;
median_begin_r <= 4'b0;
median_clk_r <= 4'b0;
end
else begin
median_de_r <= {median_de_r[2:0], Y_de};
median_hs_r <= {median_hs_r[2:0], ycbcr_hs};
median_vs_r <= {median_vs_r[2:0], ycbcr_vs};
median_pwm_r <= {median_pwm_r[2:0], ycbcr_pwm};
median_begin_r <= {median_begin_r[2:0], ycbcr_begin};
median_clk_r <= {median_clk_r[2:0], ycbcr_clk};
end
end
assign median_de = median_de_r[3];
assign median_hs = median_hs_r[3];
assign median_vs = median_vs_r[3];
assign median_pwm = median_pwm_r[3];
assign median_begin = median_begin_r[3];
assign median_clk = median_clk_r[3];
三、上板验证
滤波后