7.3.3 自适应滤波器

自适应中值滤波器

对于7.3.2节所讨论的中值滤波器,只要脉冲噪声的空间密度不大,性能还是可以的(根据经验需Pa和Pb小于0.2)。本节将证明,自适应中值滤波器可以处理更大概率的脉冲噪声。自适应中值滤波器的另一个优点是平滑非脉冲噪声时,试图保留细节,这是传统中值滤波器所做不到的。正如前面几节中所讨论的所有滤波器一样,自适应中值滤波器也工作于矩形窗口区域Sxy内。然而,与这些滤波器不同的是自适应中值滤波器在进行滤波处理时,会根据本节列举的某些条件而改变(增大或缩小)Sxy的尺寸。记住,滤波器的输出是一个单值,该值用于替代点(x,y)处的像素值,位于(x,y)处的点是Sxy的中心也是它的锚点。

考虑如下符号:

Zmin=Sxy中的最小灰度值;

Zmax=Sxy中的最大灰度值;

Zmed=Sxy中的中值;

Zxy=坐标(x,y)处的灰度值;

Smax=Sxy所允许的最大尺寸(在程序中,用kernal_size表示);

自适应中值滤波算法以两个进程工作,分别为进程A和B,如下所示:

进程A:

如果Zmin<Zmed<Zmax,则转到进程B
     否则增大窗口尺寸;
     增大后的窗口尺寸(程序中用ks表示),
     如果ks<Smax,则重复A。(在程序中,kernal_size即Smax)
     否则输出Zmed

进程B:

如果Zmin<Zxy<Zmax,则输出Zxy
     否则,输出Zmed.

该算法的设计意图是要实现3个目的:①去除椒盐噪声;②平滑其它非脉冲噪声;③减少物体边界细化或粗化的失真。Zmin和Zmax和在算法统计上,认为是类脉冲噪声分量,既使它们不是图像中的最大值或最小值。

进程A的目的是确定中值滤波器的输出Zmed,是否是一个脉冲(黑或白)。如果条件Zmin<Zmed<Zmax有效,则根据前节提到的原因,Zmed不可能是脉冲。这种情况下,转到进程B,检验窗口Sxy的中心点Zxy(即锚点)是否是一个脉冲。如果满足条件,就不是脉冲,原因与前同。这时,算法输出一个未修改的像素值Zxy。通过不修改这些“中间灰度级”的点,减少图像中的失真。如果Zmin<Zxy<Zmax为假,则Zxy=Zmin或Zxy=Zmax。在任何一种情况下,像素值都是一个极端值,且算法输出中值Zmed,从进程A可知Zmed不是脉冲噪声。最后一步是执行标准的中值滤波。问题是,标准中值滤波器使用图像中相应邻域的中值代替图像中的每一点,这会引起不必要的细节损失。

继续上面的说明,假设进程A确实找到了一个脉冲(若不是,则转到进程B),算法会增大窗口尺寸,并重复进程A。该循环会一直继续,直到算法找到一个非脉冲的中值,并转到进程B。如果循环中窗口达到了最大尺寸,则算法会返回值Zmed。注意,这并不能保证该值不是脉冲。噪声的概率Pa或Pb越小,或者在Sxy允许的范围内越大,退出条件也就越难满足。这是合理的,随着脉冲密度的增大,我们会需要更大的窗口来消除尖峰噪声。

算法没输出一个值,窗口Sxy就被移动到图像中的下一个位置。然后,算法重新初始化并应用到新位置的像素。仅使用新像素就可以反复更新中值,因而减少了计算开销。

#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
using namespace cv;
using namespace std;
//下面的宏,定义了在矩阵src的第m行、n列,ks*ks覆盖的矩形区域内的像素,并将像素压到矢量v中
//该覆盖区域的左上角坐标为(m,n),宽为ks,高为ks,要求src必须是单通道,数据类型为CV_8UC1
#define CV_ROI_ELEM(src,vector,m,n,ks) \
{ \
uchar* kn; \
int st0=src.step[];\
int st1=src.step[];\
for(int k=;k<(ks);k++) \
{ \
for(int s=;s<(ks);s++) \
{ \
kn =src.data+(k+m)*st0+(s+n)*st1; \
vector.push_back(*kn); \
} \
} \
} #define CV_MAT_ELEM2(src,dtype,y,x) \
(dtype*)(src.data+src.step[]*(y)+src.step[]*(x))
/*********************自适应中值滤波********************************/
void selfAdaptiveMedianBlur(Mat&src,Mat&dst,int kernal_size)
{
CV_Assert(src.type()==CV_8UC1||src.type()==CV_8U);
if(dst.empty())
{
dst.create(src.rows,src.cols,CV_8UC1);
}
uchar* pdst=dst.data;
uchar Zmin,Zmax,Zmed,Zxy;
int step0=src.step[];
int step1=src.step[];
for(int i=kernal_size/;i<src.rows-kernal_size/;i++)
{
for(int j=kernal_size/;j<src.cols-kernal_size/;j++)
{
int ks=;//kernal_size;
int count=;
Zxy=*CV_MAT_ELEM2(src,uchar,i,j);//Sxy覆盖区域的中心点像素值,即锚点像素值
vector<uchar> v;//将模板覆盖区域的像素,压入矢量v中
do{
if(cout==)
{//获取模板ks*ks覆盖区域的像素,压入矢量v中
CV_ROI_ELEM(src,v,i-ks/,j-ks/,ks);
}
else
{
/****************下面的for循环,将外扩的四个边的像素添加到v中**************/
uchar* p=src.data+(i-ks/)*step0+(j-ks/)*step1;
for(int u=;u<ks;u++)
{
v.push_back(*(p+u*step1));//向外扩展的四个边的上边
v.push_back(*(p+(ks-)*step0+u*step1));//向外扩展的四个边的下边
if(u!=&&u!=ks-)
{
v.push_back( *(p+u*step0));//向外扩展的四个边的左边
v.push_back(*(p+u*step0+(ks-)*step1));//向外扩展的四个边的右边
}
}
} //对v的元素排序
//排序后,Sxy覆盖区域内,最大值为Zmax=v[v.size-1],最小值为Zmin=v[0]
std::sort(v.begin(),v.end());
Zmin=v[],Zmax=v[v.size()-],Zmed=v[ks*ks/];
pdst =CV_MAT_ELEM2(dst,uchar,i,j);
if(Zmin<Zmed&&Zmed<Zmax)
{
if(Zmin<Zxy&&Zxy<Zmax)
{*pdst=Zxy;break;}
else
{*pdst=Zmed;break;}
}
else
{
ks +=;
}
count++;
}while(ks<=kernal_size); *pdst=Zmed;
}
}
} int main()
{
Mat src=imread("D:\\Qt\\MyImage\\3.bmp",);
imshow("src image",src); Mat dst;
selfAdaptiveMedianBlur(src,dst,); imshow("adaptive median filter",dst); waitKey(); return ;
}

原图像:

自适应中值滤波后的图像:

基于Opencv的自适应中值滤波函数selfAdaptiveMedianBlur()的更多相关文章

  1. opencv-11-中值滤波及自适应中值滤波

    开始之前 在上一篇我们实现了读取噪声图像, 然后 进行三种形式的均值滤波得到结果, 由于我们自己写的均值滤波未作边缘处理, 所以效果有一定的下降, 但是总体来说, 我们得到的结果能够说明我们的算法执行 ...

  2. 基于记忆性的中值滤波O(r)与O(1)复杂度的算法实现

    本文参考博客:https://www.cnblogs.com/Imageshop/archive/2013/04/26/3045672.html 原生的中值滤波是基于排序算法的,这样的算法复杂度基本在 ...

  3. verilog实现中值滤波

    前言 项目需要,想要实现算法中的其中一步即中值滤波,同时,因为图像处理部分中值滤波相对来说还是比较简单的,将中值滤波的硬件实现作为进入FPGA领域的第一次尝试.虽然说网上有较多关于中值滤波的文档,可是 ...

  4. OpenCV计算机视觉学习(4)——图像平滑处理(均值滤波,高斯滤波,中值滤波,双边滤波)

    如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice &q ...

  5. Win8Metro(C#)数字图像处理--2.10图像中值滤波

    原文:Win8Metro(C#)数字图像处理--2.10图像中值滤波  [函数名称] 图像中值滤波函数MedianFilterProcess(WriteableBitmap src) [函数代码] ...

  6. 基于MATLAB的中值滤波算法实现

    在实时图像采集中,不可避免的会引入噪声,尤其是干扰噪声和椒盐噪声,噪声的存在严重影响边缘检测的效果,中值滤波是一种基于排序统计理论的非线性平滑计数,能有效平滑噪声,且能有效保护图像的边缘信息,所以被广 ...

  7. opencv —— boxFilter、blur、GaussianBlur、medianBlur、bilateralFilter 线性滤波(方框滤波、均值滤波、高斯滤波)与非线性滤波(中值滤波、双边滤波)

    图像滤波,指在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像与处理中不可缺少的操作. 邻域算子,指利用给定像素及其周围的像素值,决定此像素的最终输出值的一种算子.线性邻域滤波器就是一种常 ...

  8. [学习opencv]高斯、中值、均值、双边滤波

    http://www.cnblogs.com/tiandsp/archive/2013/04/20/3031862.html [学习opencv]高斯.中值.均值.双边滤波 四种经典滤波算法,在ope ...

  9. 基于FPGA的中值滤波算法实现

    在这一篇开篇之前,我需要解决一个问题,上一篇我们实现了基于FPGA的均值滤波算法的实现,最后的显示效果图上发现有一些黑白色的斑点,我以为是椒盐噪声,然后在做基于FPGA的中值滤波算法的实验时,我发现黑 ...

随机推荐

  1. jquery 在将对象作为参数传递的时候要转换成 JSON

    不转换成JSON 会报错  Unexpected identifier 方法: JSON.stringify(对象)

  2. Android 腾讯bugly Tinker 热修复

    Bugly热更新是腾讯推出的热更新框架,热更新是指无需到应用市场重新下载安装app,只需要在app内下载补丁包即可实现app的更新,主要用于app的bug修复或者少量改动. 大家在使用app(特别是游 ...

  3. Java使用freemarker导出word文档

    通过freemarker,以及JAVA,导出word文档. 共分为三步: 第一步:创建模板文件 第二步:通过JAVA创建返回值. 第三步:执行 分别介绍如下: 第一步: 首先创建word文档,按照想要 ...

  4. Java分级考试

    石家庄铁道大学选课管理系统 1.项目需求: 本项目所开发的学生选课系统完成学校对学生的选课信息的统计与管理,减少数据漏掉的情况,同时也节约人力.物力和财力.告别以往的人工统计. 2.系统要求与功能设计 ...

  5. shell中的控制流结构

    shell中的控制流结构 1.if...then..else..fi语句 2.case语句 3.for循环 4.until 语句 5.while循环 6.break控制 7.continue 控制 1 ...

  6. 《Python3 标准库》作者 道格.赫尔曼

    Doug Hellmann目前是Racemi公司的一位高级开发人员,也是Python Software Foundation的信息交流主管.从1.4版开始他就一直在做Python编程,曾在大量UNIX ...

  7. SQL Server自动备份

    1.打开SQL Server Management Studio 数据库-管理-维护计划,右键,维护计划向导 2.在弹出页面右下方点击[更改],修改计划执行方案 根据需要,修改执行时间 3.修改完毕后 ...

  8. java——解决"java.io.StreamCorruptedException: invalid stream header: xxx"

    这个错误是由序列化引起的,可能的原因以及解决方法: 1.kryo对于集合(比如 Map)的反序列化会失效,报这个错误,解决办法比较暴力,不用kryo了,直接用java原生方法. 2.使用Java原生方 ...

  9. jquery attribute选择器 语法

    jquery attribute选择器 语法 作用:[attribute] 选择每个带有指定属性的元素.可以选取带有任何属性的元素(对于指定的属性没有限制). 语法:$("[attribut ...

  10. python 创建实例对象

    实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式. 以下使用类的名称 Employee 来实例化,并通过 __init__ 方法接收参数 ...