Administrator
发布于 2026-09-09 / 0 阅读
0
0

非局部均值类滤波算法

  1. 彩色图转换成灰度图
  2. 均值滤波
  3. 非局部均值滤波(ONLM)
  4. 快速非局部均值滤波(利用积分图像体现快速性)
  5. 参数h自适应NLM
  6. 一个图像的五个指标
    • 亮度:代表均值
    • 对比度:标准差
    • 信息度:商
    • 梯度
    • 空间频率
  7. 两个图的七个指标(比较两个图像)
    • 误差均方误差(MSE)
    • 误差均方根误差(RMSE)
    • 峰值信噪比(PSNR)
    • 信噪比:信息图和噪声图的能量对比
    • 相似系数(SSIM)
    • 噪声二差
    • 降噪和细节程度

非局部均值滤波简介

均值滤波,就是用周围像素点的均值来代替此点,非局部均值滤波,当前像素值由图像中所有与它相似(非局部)的像素加权平均得到。它可以在降噪的同时最大程度的保留细节成分。

由于二维的小波变换主要针对图像信号,且小波理论主要建立在函数论等基础上,那么图像信号就可看成离散的二元函数的采样。因此对于一个图像,i行j列处的值A( i , j )代表着一个索引号,根据这个索引号在索引表中可以找到实际的RGB数值

由于很多时候,小波变换必须要求索引表是线性单调的,所以解决方法之一为,根据RGB各自比重降彩色转灰色,即单色图. 下面为读取图片以及转换成灰度图代码.

%ENGLISH
%Load a mat-file containing a photograph of a colorful primate. 
% Display the indexed image using its associated colormap.

%FRANÇAIS
%Charger un fichier mat contenant un photographie d'un primate coloré
%Afficher l'image indexée en utilisant sa colormap associée

%中文
%加载一个.Mat 类型的文件,其中包含一个彩色大猩猩的图片
%通过使用对应的颜色棒来显示索引图像

%% EXEMPLE 1
clc
clear all
close all
load clown  % clown 小丑🤡
Y=X;
map1=map;

figure(1)
image(Y)
%中文
%这里注意 这时显示的图像的颜色并不正确,因为其值是索引值,而并非真正的RGB值,我们后续需要利用索引值来找到对应的RGB值,将RGB值放到图像上才可以得到正确的彩色图像

%ENGLISH
%Attention here that the colors of the image displayed at this time is not correct because the values are index values, not actual RGB
%values. We need to use these index values to find the corresponding RGB values later and place the RGB values on the image in order to
%obtain a correct color image.

%FRANÇAIS
%notez ici que les couleurs affichées à ce stade ne sont pas correct parce que la valeur est la valeur d'index au lieu de la valeur RGB
%réelles. Dans la suite, on devrai utiliser la valeur d'index pour trouver les valeur RGB correspondantes, puis placer ces valeurs RGB sur
%l'image pour obtenir une image coleur correcte

colormap(map1)
colorbar
axis off          % Remove axis ticks and numbers
axis image        % Set aspect ratio to obtain square pixels

%% EXEMPLE 2 -- method 1
clear all;clc;
load mandrill.mat
map2=map;

figure(2)
image(X)
colormap(map2)
colorbar
axis off          % Remove axis ticks and numbers
axis image        % Set aspect ratio to obtain square pixels

%中文
%直接使用gray来变成灰度图

%ENGLISH
%Directly use 'gray' to convert to grayscale image

%FRANÇAIS
%Utilisez directement 'gray' pour convertir en image en niveaux de gris

n=255; %定义灰度图的颜色级别数(这里使用了255级灰度) 也可以64级灰度
map3=gray(n);
figure(3)
image(X);
title('转化为灰度图的mandrill图像')
colormap(map3);
colorbar;
axis off          % Remove axis ticks and numbers
axis image        % Set aspect ratio to obtain square pixels

%% EXEMPLE 2 -- method 2
clear all; clc;
load mandrill.mat
map2 = map;

% Display the original color image
figure(2)
image(X)
colormap(map2)
colorbar
axis image      

%中文
%提取每个RGB值 通过加权得到灰度值  加权公式固定

%ENGLISH
%Extract each RGB value to obtain the grayscale value through weighting. The werghting formula is fixed.
%
%FRANÇAIS
%Extraire la valeur de chaque RGB et obtenir la valeur de gris en pondérant. La formule de pondération est fixée.

R=map2(:,1);  %R=reshape(R,size(X));
G=map2(:,2);  
B=map2(:,3);  

%中文
%把每列单独拿出来,得到RGB对应的值
%ENGLISH
%Take out each column separately to obtain the corresponding values of RGB
%
%FRANÇAIS
%Prenez chaque colonne séparément pour obtenir la valeur correspondantes de RGB.

R = R(X); 
G = G(X); 
B = B(X);  

%中文
%不理解 但是必须这么做,来找到实际颜色值
%ENGLISH
%Dont understand but must do so to find the actual color value
%
%FRANÇAIS
%Je comprend pas mais il faut faire comme ça pour obtenir la valeur réelle

% 使用加权公式计算灰度值
Xrgb = 0.2990 * R + 0.5870 * G + 0.1140 * B;

% 显示生成的灰度图像
figure(3)
imagesc(Xrgb);  % 使用 imagesc 显示灰度图像
colormap(gray); % 使用灰度 colormap 来正确显示灰度值
colorbar;
title('转化为灰度图的mandrill图像')
axis image      % 保持像素为正方形

%% EXEMPLE 3
clear all;clc;
load flujet
Z=X;
map4=map;
figure(4)
image(Z)
title('彩色fluid jet 图像')
colormap(map4)
colorbar
axis off         
axis image      

均值滤波算法

包含内容

原理:待处理像素值可以用临近像素的均值来代替

高斯噪音、图像边界扩展处理、均值窗的构建和移动显示、降噪点像素值的计算、输出对比

clc
clear
close all;
%% 读取原始图像
Input=imread('lena.bmp'); %read image
Input=double(Input); % convert the image to double type for subsequent processing
[m,n]=size(Input); % get the size of the image
%% 创建高斯噪声
d=30;
Gasnois=d*randn(m,n); %wgn(m,n)  generate gaussian noise with standard 30
STDgn=std(std(Gasnois));% calculate the standard of noise
MEANgn=mean(mean(Gasnois));% calculate the mean of noise

%这里要求高斯噪声的标准差为1.5 均值为0 但是经过上述检验可发现,其标准差和均值并不符合要求,所以在下面添加了几行代码来更加精确的生成高斯噪声
%一维数据进行一次std或mean 二维图像数据进行两次


a=0; 
b=1.5;
IMGgn=a+b.*((Gasnois-MEANgn)/STDgn);%把噪声拿来,减去他的均值,做差除以标准差,因此后面括号里就是均值是0 标准差是1的高斯噪音,本例生成均值=a,标准差=b的高斯噪声

%这个步骤在数学中就是标准化,比如说概率论与数理统计 给一个随机变量 想让它的均值是0 怎么办呢 让它减去原来的均值最后除以原来的标准差


STDYimg=std(std(IMGgn)); % same
MEANYimg=mean(mean(IMGgn));
Input_noise=Input+IMGgn; %add noise to the original image to obtain the final noisy-image 


WSH=2;  %1,2,3,7取均值滤波窗口半径
Input_r=padarray(Input_noise,[WSH,WSH],'replicate');%扩展输入图像矩阵  也就是边界扩展
[m2,n2] = size(Input_r);    %the size of the extended image 

% 显示原始图像,噪声图像和扩边图像
figure(1);
subplot(131); imshow(uint8(Input)); title('原始图像')
subplot(132); imshow(uint8(Input_noise)); title('含噪图像')
subplot(133); imshow(uint8(Input_r)); title('加取均值窗半径长作边界扩展图像');

整体思路为:导入一个图片,创建一个高斯噪音,并对其标准化,然后扩展图像(半径、指令等)

![image-20240821095229510](/Users/zehua/Library/Application Support/typora-user-images/image-20240821095229510.png)

for i=1:m
     for j=1:n   % 遍历整个图像长宽
         i1 = i+ WSH;  %原图右下角方向设置取均值窗
         j1 = j+ WSH;  %(i1,j1)为取均值窗中心    
         W1= Input_r(i1-WSH:i1+WSH , j1-WSH:j1+WSH); %W1为取均值窗v(Ni),长宽大小2WSH+1,中心点(i1,j1)
         [mw1,nw1] = size(W1); %中心点(i1,j1)在含噪图像中是点(i,j)。
        d = sum(sum(W1));%中心点(i1,j1)矩形v(Ni)求和
        Output_filt(i,j)=d/(mw1*nw1); %中心点(i1,j1)与点(i,j)的对应 
    end 
end
figure(2);  
subplot(131); imshow(uint8(Input)); title('原始图像')
subplot(132); imshow(uint8(Input_noise)); title('含噪图像')
subplot(133); imshow(uint8(Output_filt));title('降噪后图像');

均值滤波关键代码,不过不太重要

![image-20240821095435876](/Users/zehua/Library/Application Support/typora-user-images/image-20240821095435876.png)

MSE=sum(sum((Input_noise-Output_filt).^2))/(m*n);% calculate mean square error  between noisy image ande filtered image
%这里是含噪图像减降噪图像然后平方求和
PSNR=10*log10((255*255)/MSE);% calculate peak signal to noise ratio , is used to measure the effect of denoising. The higher the better.
% MSE =  1159   		 PSNR =  17.4899
\text{MSE} = \frac{1}{m \times n} \sum_{i=1}^{m} \sum_{j=1}^{n} \left( I(i,j) - K(i,j) \right)^2

噪声图像和去噪图像在每个位置的像素差异的平方求和后除以总像素数来得到平均平方误差。

MSE值越大,说明两图像差异越大,降噪过度,MSE值越小,降噪不明显。

\text{PSNR} = 10 \times \log_{10} \left( \frac{MAX^2}{\text{MSE}} \right)

信号峰值 (即最大像素值,此处255) 与噪声 (MSE) 的比值,并以dB为单位,*10单纯为了直观

思考问题:

  • 取均值窗半径对去噪是否存在最优值?

    对去噪有显著影响,半径大,窗大,取的均值块就大,降噪时候细节部分就抹不掉了,所以不可过大不可过小,就是最优问题

  • 怎样评价图像滤波/降噪的优势与劣势?

    峰值信噪比MSE 和 误差均方差PSNR 最后是主观视觉。但是缺少描述细节方面的指标。


非局部均值滤波

噪声分类

  • 椒盐噪声:表现为图像中的黑白点。
  • 高斯噪声:最常见且广泛分布的噪声,服从正态分布。
  • 泊松噪声:在特殊场合中出现,服从泊松分布。

图像去噪的基本方法

  • 空间域方法

    • 均值滤波
    • 高斯滤波
    • 形态学滤波
    • 非均质滤波
  • 频域方法

    • 傅立叶变换
    • 余弦变换
    • 小波分析

非局部均值滤波

该方法充分利用了图像中的冗余信息(噪声),在去噪的同时能够很好地保持图像的细节。其原理是通过图像中与当前像素点具有相似邻域结构的像素加权平均来估计当前像素点的值。

图像的噪声模型可以表示为:

v(i) = u(i) + n(i)

其中:

  • v(i) 是含噪图像
  • u(i) 是去噪后的期望图像(即没有噪声的图像)
  • n(i) 是均值为 0 的高斯白噪声

非局部均值滤波定义为:

\text{NL}v(i) = \frac{\sum_{j} w(i,j) v(j)}{\sum_{j} w(i,j)}

在像素 i 处的非局部滤波值等于与其具有相似结构的像素 j 的加权平均,其中权重 w( i , j ) 代表了它们之间的相似性。最后的结果通过归一化得到。

权重计算公式

权重的计算公式为:

w(i, j) = \exp\left(-\frac{\|v(N_i) - v(N_j)\|_{2, \alpha}^2}{h^2}\right)

其中:

  • v(N_i) - v(N_j) 衡量了在像素 i 和 j 处的图像块之间的差异,使用的是欧几里得距离。注意它最后平方又开方,只剩下欧几里得距离计算,也就是平方和。
  • h 是滤波参数。

它是一个e^(-x)函数,如果分子越大,那么相似性系数w(i, j)就越小,如果分母越大,那么w(i, j)就越大。该公式表示,如果图像块非常相似,那么差异很小,导致 w(i, j) 值很大,即权重系数越大。

image-20240821153748323 image-20240821154008864

非局部均值法去噪问题

由于是仅靠相似度且加权来去噪,所以缺乏鲁棒性。并且不相似的像素块也会被考虑在内,只是权重小一点。因此运算量也大。

由于通常使用高斯加权,而标准高斯核时各向同性的,即方向一致,这会导致忽略图像中的边缘或者底纹这中带方向的结构在滤波过程中丢失细节

最后是滤波系数h的选择,过小 -- 只有极其相似的像素才可以滤波,因此导致去噪效果不明显; 过大-- 大多像素会被认为是相似,导致图像平滑,细节丢失。

clc
clear
close all

image = imread('lena.bmp');

load IO.mat;
noisyimage = I0;


[denoisyimage] = non_local_means(image,noisyimage);
function [denoisyimage] = non_local_means(image,noisyimage)

%% step 1: Set the three paramaters of non local mean filtering
searchws  =  5;
similarws =  3;
h = 3;

if ~strcmp(class(image),'double')
    image = double(image)/255;
end

%% step 2: image border expansion (mirror reflection) to avoid edge effects

[H,W] = size(noisyimage);     % obtain the height and width of the image
zeroimage = zeros(H,W);  % use for storing denoised images

% Expand the boundaries of the image
expandimage = padarray(noisyimage,[searchws + similarws,searchws + similarws],'symmetric');  

figure(1)
subplot(131);  imshow(image); title('original image');
subplot(132);  imshow(uint8(noisyimage)); title('Noisy image');
subplot(133);   imshow(uint8(expandimage));  title('Expand image ')

%% step 3: Main loop
kernel = make_kernel(similarws);
kernel = kernel/sum(sum(kernel));

noDenoiseCount = 0;

for rowIdx=1:H
   for colIdx=1:W
       centerRow = rowIdx + searchws + similarws;
       centerCol = colIdx + searchws + similarws;
       w1 = expandimage(centerRow-similarws:centerRow+similarws,centerCol-similarws:centerCol+similarws); %相似窗口,长宽大小2WSH+1,中心点(i1,j1)
       [hw1,ww1] = size(w1);
       maxWeight = 0;
       weightedSum = 0; % weighted values of  various similar windows
       totalWeight = 0; % sum of weights
        
       searchRowMin = centerRow - searchws;
       searchRowMax = centerRow + searchws;
       searchColMin = centerCol - similarws;
       searchColMax = centerCol + similarws;

       L = 1;
       for r = searchRowMin : L :searchRowMax
           for c = searchColMin : L : searchColMax
               if(r == centerRow && c==centerCol) 
                   continue;
               end;

               w2 = expandimage(r-similarws:r+similarws , c-similarws:c+similarws);
               distance = sum(sum(kernel .* (w1-w2).*(w1-w2)));
               similarityWeight = exp(-distance/h.^2);
               weightedSum = weightedSum + similarityWeight * expandimage(r,c);
               totalWeight = totalWeight + similarityWeight;

               maxWeight = max(maxWeight,similarityWeight);
           end
       end

       weightedSum = weightedSum + maxWeight * expandimage(centerRow,centerCol);
       totalWeight = totalWeight + maxWeight;

       if totalWeight > 0
           denoisyimage(rowIdx,colIdx) = weightedSum / totalWeight;
       else
           denoisyimage(rowIdx,colIdx) = noisyimage(rowIdx,colIdx);

           noDenoiseCount = noDenoiseCount +1;
       end
   end
end

figure(4);
subplot(131);imshow(image);title('original image')
subplot(132); imshow(uint8(noisyimage)); title('noisy image')
subplot(133); imshow(uint8(denoisyimage));title('denoisy image') 

%% Calculate PSNR 

% can be encapsumated as a function

cumulative = sum(sum((double(noisyimage) - (denoisyimage)).^2)); % 2 sum ---> row and column
MSE = cumulative / prod(size(noisyimage));                   % divide by the total number of pixels  --->   obtain the mean square error of each pixel (MSE)
PSNR  = 10 * log10(255*255/MSE)


%% Calculate SNR
% can be encapsumated as a function

[row,col,nchannel] = size(noisyimage);

SNR = 0;
if nchannel == 1 % gray image
    signalenergy = sum( sum(( noisyimage - mean( mean( noisyimage ))) .^2));
    noiseenergy  = sum( sum(( noisyimage - denoisyimage ).^2));
    SNR = 10 * log10(signalenergy/noiseenergy)

elseif nchannel == 3 % coloful image
        for i = 1:3
            signalenergy = sum(sum((noisyimage(:,:,i)-mean(mean(noisyimage(:,:,i)))).^2));
            noiseenergy  = sum(sum((noisyimage(:,:,i)-denoisyimage(:,:,i)).^2));
            SNR = SNR + 10 * log10(signalenergy/noiseenergy);
        end
        SNR = SNR / 3
end

end

%% subfunction

function [kernel] = make_kernel(input)
kernel = zeros(2*input+1, 2*input+1);

for d = 1 : input
    value = 1 / (2*d+1)^2 ;
    for i = -d : d
        for j = -d : d
            kernel(input+1-i,input+1-j) = kernel(input+1-i,input+1-j) + value;

        end
    end
end

kernel = kernel./input;

end

![image-20240824105511716](/Users/zehua/Library/Application Support/typora-user-images/image-20240824105511716.png)

![image-20240824105532205](/Users/zehua/Library/Application Support/typora-user-images/image-20240824105532205.png)

PSNR = 28.1857 SNR = 13.3088

计算 PSNR

1. 计算累加

\text{cumulative} = \sum_{i=1}^{\text{row}} \sum_{j=1}^{\text{col}} \left( \text{image}(i, j) - \text{denoisyimage}(i, j) \right)^2

2. 计算 MSE

\text{MSE} = \frac{\text{cumulative}}{\text{row} \times \text{col}}

3. 计算 PSNR

\text{PSNR} = 10 \cdot \log_{10}\left(\frac{255^2}{\text{MSE}}\right)

计算 SNR

灰度图像

1. 信号能量

\text{signal energy} = \sum_{i=1}^{\text{row}} \sum_{j=1}^{\text{col}} \left( \text{image}(i, j) - \mu \right)^2

其中,μ 是图像的均值:

\mu = \frac{1}{\text{row} \times \text{col}} \sum_{i=1}^{\text{row}} \sum_{j=1}^{\text{col}} \text{image}(i, j)

2. 图像的噪声能量

\text{noisy energy} = \sum_{i=1}^{\text{row}} \sum_{j=1}^{\text{col}} \left( \text{image}(i, j) - \text{denoisyimage}(i, j) \right)^2

3. 计算信噪比 (SNR)

\text{SNR} = 10 \cdot \log_{10}\left(\frac{\text{signalenergy}}{\text{noiseenergy}}\right)

彩色图像

1. 信号能量 (对每个通道 c 进行计算)

\text{signal energy}_c = \sum_{i=1}^{\text{row}} \sum_{j=1}^{\text{col}} \left( \text{image}(i, j, c) - \mu_c \right)^2

其中,μ_c 是图像的均值:

\mu_c = \frac{1}{\text{row} \times \text{col}} \sum_{i=1}^{\text{row}} \sum_{j=1}^{\text{col}} \text{image}(i, j, c)

2. 噪声能量

\text{noisy energy}_c = \sum_{i=1}^{\text{row}} \sum_{j=1}^{\text{col}} \left( \text{image}(i, j, c) - \text{denoisyimage}(i, j, c) \right)^2

3. 计算信噪比 (SNR)

\text{SNR} = \frac{1}{3} \sum_{c=1}^{3} 10 \cdot \log_{10}\left(\frac{\text{signalenergy}_c}{\text{noiseenergy}_c}\right)

评论