非局部均值滤波算法[通俗易懂]

非局部均值滤波算法[通俗易懂]2016.09.09更新,修改了SSIM中值太大的问题首先谈一下什么是非局部均值滤波。在此之前,我们先来看一下均值滤波的原理。均值滤波均值滤波的计算非常简单,将图像像素点灰度记录在数组中,然后设置方框半径的值,然后将方框中的所有点的像素求和取平均,得到的结果就是均值滤波后对应像素点的灰度值。优点:计算很快而且简单从算法可以看出,只是求了平均,并没有很复杂的计算缺点:得到的图像很模

大家好,又见面了,我是你们的朋友全栈君。

#####2016.09.09更新,修改了SSIM中值太大的问题

首先谈一下什么是非局部均值滤波。在此之前,我们先来看一下均值滤波的原理。
#####均值滤波

均值滤波的计算非常简单,将图像像素点灰度记录在数组中,然后设置方框半径的值,然后将方框中的所有点的像素求和取平均,得到的结果就是均值滤波后对应像素点的灰度值。
优点
计算很快而且简单
从算法可以看出,只是求了平均,并没有很复杂的计算
缺点
得到的图像很模糊
当方框的半径越大,得到的图像中那些变化较大的地方(边缘)计算后变化就越小,即边缘不明显,即模糊
#####非局部均值滤波

非局部均值滤波的基本原理与均值滤波类似,都是要取平均值,但是非局部均值滤波在计算中加入了每一个点的权重值,所以能够保证在相邻且相差很大的点在方框中求平均值时相互之间的影响减小,也就对图像边缘细节部分保留很多,这样图像看起来会更清晰。非局部均值滤波的算法我认为可以大致分为以下几个步骤:

  1. 首先在一个点A周围取一个大的框(搜索框),设边长为s,A在方框的中心,然后再在方框中取小的方框,即相似框,设边长为d
  2. 那么在A周围也有一个边长为d的方框,然后在大方框中找到所有边长为d的小方框的组合(就是一个小正方形在一个大正方形中到处移动,记录小正方形中心点的坐标就行了),设小方框的中心点为B,分别于A周围的相似框求减法,并且加入高斯核计算得到的加权值,这样可以计算出一个二维数组,里面存放着各个点的差值乘以权重后的值,加入高斯核主要是因为距离中心点距离不同对中心点的影响大小也不同,而且高斯核的权重和是1,所以就不用再归一化了。
  3. 然后将这个二维数组求和并平均,得到的值就是这个相似框的中心点B对于A的权重值。计算出A周围所有点的权重值,其实这个时候这个值和权重是成反比的,以A本身为例(以A为中心点的相似框),计算出来A对于A的所谓权重值是零。然后根据计算出来的值用一个指数减函数就得到了成正比的权重关系,具体的函数见下面的代码,w=exp(-d/h),就是这个,其中d就是计算出来的值啦,代入后w就是成正比的权重关系啦,h是一个滤波百分比值。可以先固定为一个常数。 而且这个计算出来w就是一个(0,1)的值哦,自动归一化啦
  4. 然后就是根据得到的权重值以及各个点本身的灰度值计算出非局部均值滤波后A点的灰度值。
  5. 以此类推,可以计算出图中所有点经过非局部均值滤波后的值
    优点
    可以既去除噪声,又保留图像边缘细节
    当然去噪声指的一般是高斯白噪声,因为高斯白噪声的均值是0,所以求和取平均会比较有效果
    缺点
    计算起来很慢
    如果图像像素点比较多,而且计算的时候取的框还比较大的话,那么计算一般几分钟是要的了。
    下面是一段非局部均值滤波的代码:
function  [output]=NLmeansfilter(input,t,f,h)                
[m n]=size(input); 
%t:搜索框半径;f:相似框半径;h:滤波频率百分比
Output=zeros(m,n);
input2 = padarray(input,[f f],'symmetric');              
 %将边缘对称折叠上去  
 % f :加宽的宽度值
 kernel = make_kernel(f);                              %计算得到一个高斯核,用于后续的计算
 kernel = kernel / sum(sum(kernel));             %sum:对矩阵k的每一列求和,k表示矩阵k的总和
 h=h*h;
 for i=1:m
 for j=1:n
         i1 = i+ f;
         j1 = j+ f;      
         W1= input2(i1-f:i1+f , j1-f:j1+f);		
         wmax=0; 
         average=0;
         sweight=0;
         rmin = max(i1-t,f+1);      %确定相似框的边长,其实可以在代入数据的时候就设置搜索框和边界框边长的大小关系,就不用求最大最小值了
         rmax = min(i1+t,m+f);      %这段主要是控制不超出索引值
         smin = max(j1-t,f+1);
         smax = min(j1+t,n+f);
         for r=rmin:1:rmax
         for s=smin:1:smax                 
                if(r==i1 && s==j1) continue; end;      
                W2= input2(r-f:r+f , s-f:s+f);                
                d = sum(sum(kernel.*(W1-W2).*(W1-W2)));
                w=exp(-d/h);                 
                if w>wmax      
                   wmax=w;                   
                end
                sweight = sweight + w;
                average = average + w*input2(r,s);                                  
         end 
         end
        average = average + wmax*input2(i1,j1);
        sweight = sweight + wmax;       
        if sweight > 0
            output(i,j) = average / sweight;
        else
            output(i,j) = input(i,j);
        end                
 end
 end	

 
 
 function [kernel] = make_kernel(f)            %这是一个高斯核   
kernel=zeros(2*f+1,2*f+1);   
for d=1:f    
  value= 1 / (2*d+1)^2 ;    
  for i=-d:d
  for j=-d:d
    kernel(f+1-i,f+1-j)= kernel(f+1-i,f+1-j) + value ;
  end
  end
end
kernel = kernel ./ f;    


#####2016.08.09更新
这次主要更新一下图像去噪的两个评价标准:PSNR和SSIM
#####PSNR

峰值信噪比,主要用来评价算法的去噪能力,计算公式如下:
P S N R = 10 l o g 10 ( 2 n − 1 ) 2 M S E = 20 l o g 20 2 n − 1 M S E PSNR=10log_{10}\frac{(2^n-1)^2}{MSE}=20log_{20}\frac{2^n-1}{\sqrt{MSE}} PSNR=10log10MSE(2n1)2=20log20MSE
2n1

其中MSE表示原始图像和去噪图像的均方误差
M S E = 1 m n ∑ i = 1 m ∑ j = 1 n ∥ I ( i , j ) − K ( i , j ) ∥ 2 MSE=\frac{1}{mn}\sum_{i=1}^m\sum_{j=1}^n\|I(i,j)-K(i,j)\|^2 MSE=mn1i=1mj=1nI(i,j)K(i,j)2
其中m和n分别表示图像的长和宽,I和K分别表示原图和去噪后的图

从公式可以看出,PSNR的值越大,表示去噪的效果越好

求PSNR的代码如下:

    function PSNR=PSNR_work(I,In)
    %I:滤波后的图像,In:加噪声后的图像
    I=im2double(I);
    In=im2double(In);
    [m,n]=size(I);
    MSE=0;
    for i=1:m
        for j=1:n
            MSE=MSE+(I(i,j)-In(i,j))*(I(i,j)-In(i,j));
        end
    end
    MSE=sqrt(MSE/(m*n));
    MAX=1;   %特指8位的灰度图 2^8-1=255,在matlab中归一化后取1
    PSNR=20*log10(MAX/MSE);
    end

代码中没有考虑到I和In大小不同的情况,所以当出现大小不同时,求出来的值没有意义
#####SSIM

结构相似性,用来判断两幅图像的相似性程度的,也可以作为判断去噪效果的评价指标,计算公式如下:
S S I M ( X , Y ) = ( 2 μ x μ y + C 1 ) ( 2 σ X σ Y + C 2 ) ( σ X Y 2 + C 3 ) ( μ X 2 + μ Y 2 + C 1 ) ( σ X 2 + σ Y 2 + C 2 ) ( σ X σ Y + C 3 ) SSIM(X,Y)=\frac{(2\mu_x\mu_y+C_1)(2\sigma_X\sigma_Y+C_2)(\sigma_{XY}^2+C_3)}{(\mu_X^2+\mu_Y^2+C_1)(\sigma_X^2+\sigma_Y^2+C_2)(\sigma_X\sigma_Y+C_3)} SSIM(X,Y)=(μX2+μY2+C1)(σX2+σY2+C2)(σXσY+C3)(2μxμy+C1)(2σXσY+C2)(σXY2+C3)
或者
S S I M ( X , Y ) = ( 2 μ X μ Y + C 1 ) ( 2 σ X Y 2 + C 2 ) ( μ X 2 + μ Y 2 + C 1 ) ( σ X 2 + σ Y 2 + C 2 ) SSIM(X,Y)=\frac{(2\mu_X\mu_Y+C_1)(2\sigma_{XY}^2+C_2)}{(\mu_X^2+\mu_Y^2+C_1)(\sigma_X^2+\sigma_Y^2+C_2)} SSIM(X,Y)=(μX2+μY2+C1)(σX2+σY2+C2)(2μXμY+C1)(2σXY2+C2)
两个公式中的 C 1 = ( K 1 L ) 2 C_1=(K_1L)^2 C1=(K1L)2, C 2 = ( K 2 L ) 2 C_2=(K_2L)^2 C2=(K2L)2,第一个公式中的 C 3 = C 2 / 2 C_3=C_2/2 C3=C2/2
其中, K 1 = 0.01 K_1=0.01 K1=0.01, K 2 = 0.03 K_2=0.03 K2=0.03,对于8位的图像来说, L = 2 8 − 1 = 255 L=2^8-1=255 L=281=255
两个公式都能表示图像的结构相似性,只是取值范围不同,第一个公式的取值范围在[0,1],第二个公式为[-1,1],两个公式中都是等于1的时候表示两幅图像完全相同

其中平均值和方差的计算公式如下:
μ X = 1 m ∗ n ∑ i = 1 m ∑ j = 1 n X ( i , j ) \mu_X=\frac{1}{m*n}\sum_{i=1}^m \sum_{j=1}^n X(i,j) μX=mn1i=1mj=1nX(i,j)
σ X 2 = 1 m ∗ n − 1 ∑ i = 1 m ∑ j = 1 n ( X ( i , j ) − μ X ) 2 \sigma_X^2=\frac{1}{m*n-1}\sum_{i=1}^m \sum_{j=1}^n (X(i,j)-\mu_X)^2 σX2=mn11i=1mj=1n(X(i,j)μX)2
σ X Y 2 = 1 m ∗ n − 1 ∑ i = 1 m ∑ j = 1 n ( X ( i , j ) − μ X ) ( Y ( i , j ) − μ Y ) \sigma_{XY}^2=\frac{1}{m*n-1}\sum_{i=1}^m\sum_{j=1}^n(X(i,j)-\mu_X)(Y(i,j)-\mu_Y) σXY2=mn11i=1mj=1n(X(i,j)μX)(Y(i,j)μY)
计算SSIM的代码如下:

function SSIM=SSIM_work(I,In)
%I:原始图像 In:加了噪声后的图像
I=im2double(I);In=im2double(In);
miu_x=0;miu_y=0;
%miu_x:I的平均值 miu_y:In的平均值
sigma_x=0;sigma_y=0;sigma_xy=0;
%sigma_x:I的方差  sigma_y:In的方差  sigma_xy:I和In的协方差
k1=0.01;k2=0.03;
L=1; %在MATLAB中由于对灰度值的归一化所以这里取1
c1=(k1*L)*(k1*L);c2=(k2*L)*(k2*L);c3=c2/2;
%c1:用来维持稳定的常数  c2:用来维持稳定的常数
[m,n]=size(I);
for i=1:m
    for j=1:n
        miu_x=miu_x+I(i,j);
        miu_y=miu_y+In(i,j);
    end
end
miu_x=miu_x/(m*n);
miu_y=miu_y/(m*n);
for k=1:m
    for l=1:n
        sigma_x=sigma_x+(I(k,l)-miu_x)^2;
        sigma_y=sigma_y+(In(k,l)-miu_y)^2;
        sigma_xy=sigma_xy+(I(k,l)-miu_x)*(In(k,l)-miu_y);
    end
end
sigma_x=sigma_x/(m*n-1);sigma_y=sigma_y/(m*n-1);
sigma_xy=sigma_xy/(m*n-1);
sigma_x=sqrt(sigma_x);sigma_y=sqrt(sigma_y);
%sigma_xy=sqrt(sigma_xy);
l_xy=(2*miu_x*miu_y+c1)/(miu_x^2+miu_y^2+c1);
c_xy=(2*sigma_x*sigma_y+c2)/(sigma_x^2+sigma_y^2+c2);
s_xy=(sigma_xy*sigma_xy+c3)/(sigma_x*sigma_y+c3);
SSIM=l_xy*c_xy*s_xy;
%SSIM=(2*miu_x*miu_y+c1)*(2*sqrt(sigma_xy)+c2)/((miu_x^2+miu_y^2+c1)*(sigma_x+sigma_y+c2));
end

这样,用PSNR和SSIM就能评价非局部均值的去噪能力了,当然,还是需要一个对比来显示出非局部均值算法的去噪能力,这里先写了一个简单的均值滤波,代码如下:

function [Im]=Average_Filter(I,r)
%I:原始图像 r:框半径
In=padarray(I,[r,r],'symmetric');
In=im2double(In);
[m,n]=size(I);
Im=zeros(m,n);
for i=1:m
    for j=1:n
        c_i=i+r;
        c_j=j+r;
        sum=0;
        for k=c_i-r:1:c_i+r
            for l=c_j-r:1:c_j+r;
                sum=sum+In(k,l);
            end
        end
        sum=sum/(2*r+1)^2;
        if sum>0
        Im(i,j)=sum;
        else 
        Im(i,j)=I(i,j);
        end
    end
end

得到的实验结果如下:
原始图像高斯噪声0.01相似窗口半径2
三幅图分别为原始图像,加了方差为0.01的高斯白噪声后的图像和非局部均值滤波后的图像,用评价指标评价的结果如下:
噪声图像:PSNR–>20.3265,SSIM–>0.9156
滤波图像:PSNR–>31.0105,SSIM–>0.9924
从图像和数据上可以看出,滤波后的图像噪点减少很多,清晰度有所下降,图像整体观感提升很多

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/143690.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 爬虫基本知识,如何发起请求,进行分析

    爬虫基本知识,如何发起请求,进行分析爬虫基础知识爬虫一个实战性很强的内容,下面是一些知识点,方便日后复习,具体还要去案例看看,随机应变。这是我的github爬虫仓库,欢迎大家clone进行学习和体验。一.网络爬虫概述定义网络蜘蛛(spider)、网络机器人(robot),抓取网络数据的程序其实就是用Python程序模仿人点击浏览器并访问网站,而且模仿的越像越好,让Web站点无法发现你不是人爬取数据的目的1、公司项目测试数据2、公司业务部门及其他部门所需数据3、数据分析企业获取数据方式1、公司自有数据2、第三方

    2022年10月3日
    0
  • Python爬虫开发学习全教程第二版,爆肝十万字【建议收藏】

    Python爬虫开发学习全教程第二版,爆肝十万字【建议收藏】大家好,我是辣条。上次整理的爬虫教程反响不错,但是还是有小伙伴表示不够细致,今天带了升级版,全文很长,建议先收藏下来。一、爬虫基础爬虫概述知识点: 了解爬虫的概念 了解爬虫的作用 了解爬虫的分类 掌握爬虫的流程 1.爬虫的概念模拟浏览器,发送请求,获取响应网络爬虫(又被称为网页蜘蛛,网络机器人)就是模拟客户端(主要指浏览器)发送网络请求,接收请求响应,一种按照一定的规则,自动地抓取互联网信息的程序。 原则上,只要是客户端(浏

    2022年5月30日
    23
  • SSTI 学习笔记

    SSTI 学习笔记PHPSSTI(Twig)学习文章进入环境,左上角有flag,hint都检查看看flag页面显示ip,hint页面源代码有提示考虑XFF头或者referer头测试一下注:这里不用加上“;”出来了pythonflaskssti学习文章原理:因为对输入的字符串控制不足,把输入的字符串当成命令执行。漏洞产生主要原因:render_template渲染函数的问题渲染函数在渲染的时候,往往对用户输入的变量不做渲染,..

    2022年10月21日
    0
  • 软件测试缺陷报告_软件测试缺陷分析

    软件测试缺陷报告_软件测试缺陷分析软件缺陷一、软件缺陷定义二、常见的软件缺陷三、软件缺陷产生原因四、软件缺陷的生命周期五、软件缺陷报告应包含的内容六、缺陷报告模板七、企业案例分析案例1缺陷描述案例2缺陷标题提炼Author:lucky多多转载请注明出处!一、软件缺陷定义软件缺陷是计算机或程序中存在的会导致用户不能或者不方便完成功能的问题、错误、或者隐藏的功能缺陷。缺陷的存在会导致产品在某种程度上不能满足用户的需要IEEE…

    2022年9月16日
    0
  • 如何正确的理解RPN网络的train和test[通俗易懂]

    如何正确的理解RPN网络的train和test[通俗易懂]刚开始学FasterRCNN时,遇到这么一个困惑不知其他人有没有:RPN网络在程序中的训练是如何进行的?它都训练了网络中的哪些部分?其实这些我们如果不看源码都很难真正理解!我们以Faster-RCNN_TF的源码为例,以下代码取自./lib/networks/VGGnet_train.py#=========RPN============#以下代码的先后顺序我调整了一下,便…

    2022年6月23日
    24
  • 如何查看linux操作系统版本号_如何查看centos版本

    如何查看linux操作系统版本号_如何查看centos版本Linux系统自问世后,产生了各种分支,目前主流的操作系统版本有reahat,Centos,Ubuntu,debian,Suselinux等,不同操作系统命令上也稍有区别,那么在linux主机上,我们怎么查看操作系统的版本号呢?工具/原料 xshell6 Centos7 方法/步骤 方式一:通过命令cat/etc/redhat-release,主要针对redhat系列,redhat,centos都可以通过此命令查看。 方式二:如下方法即可查看操作系统版本,

    2022年9月15日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号