一、图像去噪及滤波简介

1 图像去噪

1.1 图像噪声定义

噪声是干扰图像视觉效果的重要因素,图像去噪是指减少图像中噪声的过程。噪声分类有三种:加性噪声,乘性噪声和量化噪声。我们用f(x,y)表示图像,g(x,y)表示图像信号,n(x,y)表示噪声。

图像去噪是指减少数字图像中噪声的过程。现实中的数字图像在数字化和传输过程中常受到成像设备与外部环境噪声干扰等影响,称为含噪图像或噪声图像。去噪是图像处理研究中的一个重点内容。在图像的获取、传输、发送、接收、复制、输出等过程中,往往都会产生噪声,其中的椒盐噪声是比较常见的一种噪声,它属于加性噪声。

1.2 图像噪声来源

(1)图像获取过程中

图像传感器CCD和CMOS采集图像过程中受传感器材料属性、工作环境、电子元器件和电路结构等影响,会引入各种噪声。

(2)图像信号传输过程中

传输介质和记录设备等的不完善,数字图像在其传输记录过程中往往会受到多种噪声的污染。

1.3 噪声分类

噪声按照不同的分类标准可以有不同的分类形式:

基于产生原因:内部噪声,外部噪声。

基于噪声与信号的关系:

加性噪声:加性噪声和图像信号强度是不相关的,这类带有噪声的图像g可看成为理想无噪声图像f与噪声n之和:

g = f + n;

乘性嗓声:乘性噪声和图像信号是相关的,往往随图像信号的变化而变化,载送每一个象素信息的载体的变化而产生的噪声受信息本身调制。在某些情况下,如信号变化很小,噪声也不大。为了分析处理方便,常常将乘性噪声近似认为是加性噪声,而且总是假定信号和噪声是互相统计独立。

g = f + f*n

按照基于统计后的概率密度函数:

是比较重要的,主要因为引入数学模型这就有助于运用数学手段去除噪声。在不同场景下噪声的施加方式都不同,由于在外界的某种条件下,噪声下图像-原图像(没有噪声时)的概率密度函数(统计结果)服从某种分布函数,那么就把它归类为相应的噪声。下面将具体说明基于统计后的概率密度函数的噪声分类及其消除方式。

1.4 图像去噪算法的分类

(1)空间域滤波

空域滤波是在原图像上直接进行数据运算,对像素的灰度值进行处理。常见的空间域图像去噪算法有邻域平均法、中值滤波、低通滤波等。

(2)变换域滤波

图像变换域去噪方法是对图像进行某种变换,将图像从空间域转换到变换域,再对变换域中的变换系数进行处理,再进行反变换将图像从变换域转换到空间域来达到去除图像嗓声的目的。将图像从空间域转换到变换域的变换方法很多,如傅立叶变换、沃尔什-哈达玛变换、余弦变换、K-L变换以及小波变换等。而傅立叶变换和小波变换则是常见的用于图像去噪的变换方法。

(3)偏微分方程

偏微分方程是近年来兴起的一种图像处理方法,主要针对低层图像处理并取得了很好的效果。偏微分方程具有各向异性的特点,应用在图像去噪中,可以在去除噪声的同时,很好的保持边缘。偏微分方程的应用主要可以分为两类:一种是基本的迭代格式,通过随时间变化的更新,使得图像向所要得到的效果逐渐逼近,这种算法的代表为Perona和Malik的方程,以及对其改进后的后续工作。该方法在确定扩散系数时有很大的选择空间,在前向扩散的同时具有后向扩散的功能,所以,具有平滑图像和将边缘尖锐化的能力。偏微分方程在低噪声密度的图像处理中取得了较好的效果,但是在处理高噪声密度图像时去噪效果不好,而且处理时间明显高出许多。

(4)变分法

另一种利用数学进行图像去噪方法是基于变分法的思想,确定图像的能量函数,通过对能量函数的最小化工作,使得图像达到平滑状态,现在得到广泛应用的全变分TV模型就是这一类。这类方法的关键是找到合适的能量方程,保证演化的稳定性,获得理想的结果。

形态学噪声滤除器将开与闭结合可用来滤除噪声,首先对有噪声图像进行开运算,可选择结构要素矩阵比噪声尺寸大,因而开运算的结果是将背景噪声去除;再对前一步得到的图像进行闭运算,将图像上的噪声去掉。据此可知,此方法适用的图像类型是图像中的对象尺寸都比较大,且没有微小细节,对这类图像除噪效果会较好。

2 中值滤波

(1)概念:

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_图像去噪

(2)原理解释:

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_图像去噪_02

3 均值滤波

均值滤波是指任意一点的像素值,都是周围 N \times M 个像素值的均值。例如下图中,红色点的像素值是其周围蓝色背景区域像素值之和除25,25=5\times5 是蓝色区域的大小。

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_小波变换_03

均值滤波详细的计算方法如下图所示:

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_图像去噪_04

其中5\times5的矩阵称为核,针对原始图像内的像素点,采用核进行处理,得到结果图像,如下图所示:

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_去噪_05

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_小波变换_06

提取 1/25 可以将核转换为如下形式:

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_去噪_07

4 维纳滤波

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_去噪_08

5 小波滤波

随着小波理论的日益完善,其以自身良好的时频特性在图像去噪领域受到越来越多的关注,开辟了用非线性方法去噪的先河。具体来说,小波能够去噪主要得益于小波变换有如下特点:

(1)低熵性。小波系数的稀疏分布,使图像变换后的熵降低。 意思是对信号(即图像)进行分解后,有更多小波基系数趋于0(噪声),而信号主要部分多集中于某些小波基,采用阈值去噪可以更好的保留原始信号。

(2)多分辨率特性。由于采用了多分辨方法,所以可以非常好地刻画信号的非平稳性,如突变和断点等(例如0-1突变是傅里叶变化无法合理表示的),可以在不同分辨率下根据信号和噪声的分布来消除噪声。

(3)去相关性。小波变换可对信号去相关,且噪声在变换后有白化趋势,所以小波域比时域更利于去噪。

(4)基函数选择灵活。小波变换可灵活选择基函数,也可根据信号特点和去噪要求选择多带小波和小波包等(小波包对高频信号再次分解,可提高时频分辨率),对不同场合,选择不同小波基函数。

根据基于小波系数处理方式的不同,常见去噪方法可分为三类:

(1)基于小波变换模极大值去噪(信号与噪声模极大值在小波变换下会呈现不同变化趋势)

(2)基于相邻尺度小波系数相关性去噪(噪声在小波变换的各尺度间无明显相关性,信号则相反)

(3)基于小波变换阈值去噪

小波去噪实现步骤:

(1)二维信号的小波分解。选择一个小波和小波分解的层次N,然后计算信号s到第N层的分解。

(2)对高频系数进行阈值量化。对于从1~N的每一层,选择一个阈值,并对这一层的高频系数进行软阈值量化处理。

(3)二维小波重构。根据小波分解的第N层的低频系数和经过修改的从第一层到第N的各层高频系数,计算二维信号的小波重构。

二、部分源代码

function varargout = main(varargin)
% MAIN MATLAB code for main.fig
% MAIN, by itself, creates a new MAIN or raises the existing
% singleton*.
%
% H = MAIN returns the handle to a new MAIN or the handle to
% the existing singleton*.
%
% MAIN('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in MAIN.M with the given input arguments.
%
% MAIN('Property','Value',...) creates a new MAIN or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before main_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to main_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help main

% Last Modified by GUIDE v2.5 20-Apr-2021 22:48:39

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @main_OpeningFcn, ...
'gui_OutputFcn', @main_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before main is made visible.
function main_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to main (see VARARGIN)

% Choose default command line output for main
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes main wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = main_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;


% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%% 读取图像
[filename, pathname] = uigetfile(...
{'*.bmp;*.jpg; *.png; *.jpeg; ','Image Files(*.bmp,*.jpg,*.png,*.jpeg)';...
'*.*', 'All Files(*.*)' }...
, 'Pick an image');%打开文件 选择图像
if isequal(filename,0) || isequal(pathname,0)
return;% 果点了“ 消”
end
axes(handles.axes1);%重要,在哪个坐标轴显示图像
fpath = [pathname filename];%路径名和文件名
img1 = imread(fpath);%读取图像
imshow(img1);%显示图像
handles.img1=img1;
title('原图')
guidata(hObject, handles);
% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton2 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%% 高斯噪声
img1=handles.img1;
img2 = imnoise(img1,'gaussian'); %加高斯噪声
axes(handles.axes2);
imshow(img2);
handles.img2=img2;
title('高斯噪声图')
guidata(hObject, handles);
function [zipped, info] = huffencode(vector)
% 输入和输出都是 uint8 格式
% info 返回解码需要的结构信息
% info.pad 是添加的比特数
% info.huffcodes Huffman 码字
% info.rows 是原始图像行数
% info.cols 是原始图像列数
% info.length 是原始图像数据长度
% info.maxcodelen 是最大码长

if ~isa(vector, 'uint8')
error('input argument must be a uint8 vector');
end

[m, n] = size(vector);
vector = vector(:)';%
f = frequency(vector); %计算各符号出现的概率
symbols = find(f~=0);
f = f(symbols);
[f, sortindex] = sort(f); %将符号按照出现的概率大小排列
symbols = symbols(sortindex);
len = length(symbols);
symbols_index = num2cell(1:len);
codeword_tmp = cell(len, 1);

% 生成 Huffman 树,得到码字编码表
while length(f)>1
index1 = symbols_index{1};
index2 = symbols_index{2};
codeword_tmp(index1) = addnode(codeword_tmp(index1), uint8(0));
codeword_tmp(index2) = addnode(codeword_tmp(index2), uint8(1));
f = [sum(f(1:2)),f(3:end)];
symbols_index = [{[index1, index2]},symbols_index(3:end)];
[f, sortindex] = sort(f);
symbols_index = symbols_index(sortindex);
end
codeword = cell(256, 1);
codeword(symbols) = codeword_tmp;
len = 0;
for index = 1:length(vector) %得到整个图像所有比特数
len = len + length(codeword{double(vector(index))+1});
end
string = repmat(uint8(0), 1, len);
pointer = 1;
for index = 1:length(vector) %对输入图像进行编码
code = codeword{double(vector(index))+1};
len = length(code);
string(pointer + (0:len-1))=code;
pointer = pointer + len;
end
len = length(string);
pad = 8-mod(len, 8);
if pad > 0
string = [string uint8(zeros(1, pad))];
end
codeword = codeword(symbols);
codelen = zeros(size(codeword));
weights = 2.^(0:23);
maxcodelen = 0;
for index = 1:length(codeword)
len = length(codeword{index});
if len > maxcodelen;
maxcodelen = len;
end
if len > 0
code = sum(weights(codeword{index} == 1));
code = bitset(code, len + 1);
codeword{index} = code;
codelen(index) = len;
end
end
codeword = [codeword{:}];

%计算压缩的向量
cols = length(string)/8;
string = reshape(string, 8, cols);
weights = 2.^(0: 7);
zipped = uint8(weights * double(string));

%码表存储到一个希疏矩阵
huffcodes = sparse(1, 1);
for index = 1:nnz(codeword) % length(codeword) %numel(codeword)
huffcodes(codeword(index), 1) = symbols(index);
end

%填写解码时所需的结构信息
info.pad = pad;
info.huffcodes = huffcodes;
info.ratio = cols./length(vector);
info.length = length(vector);
info.maxcodelen = maxcodelen;
info.rows = m;
info.cols = n;

%函数addnode添加节点
function codeword_new = addnode(codeword_old, item)
codeword_new = cell(size(codeword_old));
for index = 1:length(codeword_old)
codeword_new{index} = [item codeword_old{index}];
end

%函数frequency计算各符号出现的概率
function f = frequency(vector)
if ~isa(vector, 'uint8')
error('input argument must be a uint8 vector');
end
f = repmat(0, 1, 256);
len = length(vector);
for index = 0:255
f(index+1) = sum(vector == uint8(index));
end
f = f./len; %归一化
function y = jpegencode(x, quality)
%jpegencode函数用来压缩图像,x为输入图像
%quality决定了截去的系数和压缩比

error(nargchk(1, 2, nargin)); %检查输入参数
if nargin < 2
quality = 1; %默认时 quality为1
end
x = double(x) - 128; %像素层次移动-128
[xm, xn] = size(x); %得到像素尺寸
t = dctmtx(8); %得到8*8DCT矩阵
%将图像分割成8*8子图像,进行DCT,然后进行量化
y = blkproc(x, [8,8], 'P1*x*P2', t, t');%
m = [16 11 10 16 24 40 51 61 %JPEG量化步长矩阵
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 110 103 99]*quality;
%用量化步长矩阵m对变换矩阵进行量化
yy = blkproc(y, [8, 8], 'round(x./P1)', m);
y = im2col(yy, [8, 8], 'distinct'); %将图像块排列成向量
xb = size(y, 2); %得到列数,也就是子图像个数
order = [1 9 2 3 10 17 25 18 11 4 5 12 19 26 33 ... %变换系数排列次序
41 34 27 20 13 6 7 14 21 28 35 42 49 57 50 ...
43 36 29 22 15 8 16 23 30 37 44 51 58 59 52 ...
45 38 31 24 32 39 46 53 60 61 54 47 40 48 55 62 63 56 64];
%用Z形扫描方式对变换系数重新排列
y = y(order, :);
eob = max(x(:)) + 1; %创建一个块结束符号
num = numel(y) + size(y, 2);
r = zeros(num, 1);
count = 0;
%将非零元素重新排列放入r中,-26-3 eob -25 1 eob
for j = 1: xb %每次对一列(即一块)进行操作
i = max(find(y(:, j))); %找最后一个非零元素
if isempty(i) %没有非零元素
i = 0;
end
p = count + 1;
q = p + i;
r(p: q) = [y(1: i, j); eob]; %截去零并加上结束符号
count = count + i + 1;
end
r((count + 1): end) = []; %删除r的没有用的部分
r = r + 128;
%保存编码信息
y.size = uint16([xm, xn]);
y.numblocks = uint16(xb);
y.quality = uint16(quality*100);
%对r进行Huffman编码
[y.huffman, y.info] = huffencode(uint8(r));

三、运行结果

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_小波变换_09

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_小波变换_10

【图像去噪】基于matlab GUI中值+均值+维纳+小波滤波图像去噪【含Matlab源码 800期】_去噪_11

四、matlab版本及参考文献

1 matlab版本

2014a

2 参考文献

[1] 蔡利梅.MATLAB图像处理——理论、算法与实例分析[M].清华大学出版社,2020.

[2]杨丹,赵海滨,龙哲.MATLAB图像处理实例详解[M].清华大学出版社,2013.

[3]周品.MATLAB图像处理与图形用户界面设计[M].清华大学出版社,2013.

[4]刘成龙.精通MATLAB图像处理[M].清华大学出版社,2015.

[5]基于matlab的传统算法图像去噪的实现原理