[快速阅读九] 自适应中值滤波及保守滤波在去除椒盐噪音或脉冲噪音上的应用。

news/2024/11/6 17:34:28/文章来源:https://www.cnblogs.com/Imageshop/p/18524634

  这两个滤波器也是很久前就看过的,最近偶然翻起那本比较经典的matlab数字图像处理(冈萨雷斯)书,里面也提到了这个算法,觉得效果还行,于是也还是稍微整理下。

  为了自己随时翻资料舒服和省事省时,这个算法的原理我们还是把他从别人的博客里搬过来吧:

  摘自:图像处理基础(2):自适应中值滤波器(基于OpenCV实现) 

  自适应的中值滤波器也需要一个矩形的窗口Sxy,和常规中值滤波器不同的是这个窗口的大小会在滤波处理的过程中进行改变(增大)。需要注意的是,滤波器的输出是一个像素值,该值用来替换点(x,y)处的像素值,点(x,y)是滤波窗口的中心位置。

     

原理说明

  过程A的目的是确定当前窗口内得到中值Zmed是否是噪声。如果Zmin<Zmed<Zmax,则中值Zmed不是噪声,这时转到过程B测试,当前窗口的中心位置的像素Zxy是否是一个噪声点。如果Zmin<Zxy<Zmax,则Zxy不是一个噪声,此时滤波器输出Zxy;如果不满足上述条件,则可判定Zxy是噪声,这是输出中值Zmed(在A中已经判断出Zmed不是噪声)。

  如果在过程A中,得到则Zmed不符合条件Zmin<Zmed<Zmax,则可判断得到的中值Zmed是一个噪声。在这种情况下,需要增大滤波器的窗口尺寸,在一个更大的范围内寻找一个非噪声点的中值,直到找到一个非噪声的中值,跳转到B;或者,窗口的尺寸达到了最大值,这时返回找到的中值,退出。

  从上面分析可知,噪声出现的概率较低,自适应中值滤波器可以较快的得出结果,不需要去增加窗口的尺寸;反之,噪声的出现的概率较高,则需要增大滤波器的窗口尺寸,这也符合种中值滤波器的特点:噪声点比较多时,需要更大的滤波器窗口尺寸。

  摘抄完成..............................................

  这个过程理解起来也不是很困难,图像处理基础(2):自适应中值滤波器(基于OpenCV实现) 这个博客也给出了参考代码,不过我很遗憾的告诉大家,这个博客的效果虽然可以,但是编码和很多其他的博客一样,是存在问题的。

  核心在这里:

for (int j = maxSize / 2; j < im1.rows - maxSize / 2; j++){for (int i = maxSize / 2; i < im1.cols * im1.channels() - maxSize / 2; i++){im1.at<uchar>(j, i) = adaptiveProcess(im1, j, i, minSize, maxSize);}}

  他这里的就求值始终是对同一份图,这样后续的处理时涉及到的领域实际上前面的部分已经是被修改的了,不符合真正的原理的。 至于为什么最后的结果还比较合适,那是因为这里的领域相关性不是特别强。

  我这里借助于最大值和最小值滤波以及中值滤波,一个简单的实现如下所示:

/// <summary>
/// 实现图像的自使用中值模糊。更新时间2015.3.11。
/// 参考:Adaptive Median Filtering Seminar Report By: PENG Lei (ID: 03090345)
/// </summary>
/// <param name="Src">需要处理的源图像的数据结构。</param>
/// <param name="Dest">保存处理后的图像的数据结构。</param>
/// <param name="Radius">滤波的半径,有效范围[1,127]。</param>
/// <remarks> 1: 能处理8位灰度和24位及32位图像。</remarks>
/// <remarks> 2: 半径大于10以后基本没区别了。</remarks>
int IM_AdaptiveMedianFilter(unsigned char* Src, unsigned char* Dest, int Width, int Height, int Stride, int MinRadius, int MaxRadius)
{int Channel = Stride / Width;if ((Src == NULL) || (Dest == NULL))                    return IM_STATUS_NULLREFRENCE;if ((Width <= 0) || (Height <= 0))                        return IM_STATUS_INVALIDPARAMETER;if ((MinRadius <= 0) || (MaxRadius <= 0))                return IM_STATUS_INVALIDPARAMETER;if ((Channel != 1) && (Channel != 3))                    return IM_STATUS_NOTSUPPORTED;int Status = IM_STATUS_OK;int Threshold = 10;if (MinRadius > MaxRadius)    IM_Swap(MinRadius, MaxRadius);bool AllProcessed = false;unsigned char* MinValue = (unsigned char*)malloc(Height * Stride * sizeof(unsigned char));unsigned char* MaxValue = (unsigned char*)malloc(Height * Stride * sizeof(unsigned char));unsigned char* MedianValue = (unsigned char*)malloc(Height * Stride * sizeof(unsigned char));unsigned char* Flag = (unsigned char*)malloc(Height * Width * sizeof(unsigned char));if ((MinValue == NULL) || (MaxValue == NULL) || (MedianValue == NULL) || (Flag == NULL)){Status = IM_STATUS_OUTOFMEMORY;goto FreeMemory;}memset(Flag, 0, Height * Width * sizeof(unsigned char));if (Channel == 1){//    The median filter starts at size 3-by-3 and iterates up to size MaxRadius-by-MaxRadiusfor (int Z = MinRadius; Z <= MaxRadius; Z++){Status = IM_MinFilter(Src, MinValue, Width, Height, Stride, Z);if (Status != IM_STATUS_OK)        goto FreeMemory;Status = IM_MaxFilter(Src, MaxValue, Width, Height, Stride, Z);if (Status != IM_STATUS_OK)        goto FreeMemory;        Status = IM_MedianBlur(Src, MedianValue, Width, Height, Stride, Z, 50);if (Status != IM_STATUS_OK)        goto FreeMemory;for (int Y = 0; Y < Height; Y++){int Index = Y * Stride;int Pos = Y * Width;for (int X = 0; X < Width; X++, Index++, Pos++){if (Flag[Pos] == 0){int Min = MinValue[Index], Max = MaxValue[Index], Median = MedianValue[Index];if ((Median > Min + Threshold) && (Median < Max - Threshold)){int Value = Src[Index];if ((Value > Min + Threshold) && (Value < Max- Threshold)){Dest[Index] = Value;}else{Dest[Index] = Median;}Flag[Pos] = 1;}}}}AllProcessed = true;for (int Y = 0; Y < Height; Y++){int Pos = Y * Width;for (int X = 0; X < Width; X++){if (Flag[Pos + X] == 0)        //    检测是否每个点都已经处理好了
                    {AllProcessed = false;break;}}if (AllProcessed == false) break;}if (AllProcessed == true) break;}/*    Output zmed for any remaining unprocessed pixels. Note that thiszmed was computed using a window of size Smax-by-Smax, which isthe final value of k in the loop.*/if (AllProcessed == false){for (int Y = 0; Y < Height; Y++){int Index = Y * Stride;int Pos = Y * Width;for (int X = 0; X < Width; X++){if (Flag[Pos + X] == 0)    Dest[Index + X] = Src[Index + X];}}}}else{}
FreeMemory:if (MinValue != NULL)        free(MinValue);if (MaxValue != NULL)        free(MaxValue);if (MedianValue != NULL)    free(MedianValue);if (Flag != NULL)            free(Flag);return Status;
}

  注意这里,我们还做了适当的修改,增加了一个控制阈值Threshold,把原先的 if ((Median > Min) && (Median < Max))

修改为:

  if ((Median > Min + Threshold) && (Median < Max - Threshold))

  也可以说是对应用场景的一种扩展,增加了函数的韧性。

  当我们的噪音比较少时,这个函数会很快收敛,也就是不需要进行多次的计算的。

  另外还有一个算法叫Conservative Smoothing,翻译成中文可以称之为保守滤波,这个算法在https://homepages.inf.ed.ac.uk/rbf/HIPR2/csmooth.htm有较为详细的说明,其基本原理是:

 This is accomplished by a procedure which first finds the minimum and maximum intensity values of all the pixels within a windowed region around the pixel in question. If the intensity of the central pixel lies within the intensity range
spread of its neighbors, it is passed on to the output image unchanged. However, if the central pixel intensity is greater than the maximum value, it is set equal to the maximum value; if the central pixel intensity is less than the minimum value,
it is set equal to the minimum value. Figure 1 illustrates this idea.


  

   比如上图的3*3领域,除去中心点之外的8个点其最大值为127,最小值是115,而中心点的值150大于这个最大值,所以中心点的值会被修改为127。

  注意这里和前面的自适应中值滤波有一些不同。

  1、虽然他也利用到了领域的最大值和最小值,但是这个领域是不包含中心像素本身的,这个和自适应中值是最大的区别。

       2、这个算法在满足某个条件时,不是用中值代替原始像素,而是用前面的改造的最大值或者最小值。

  3、这个算法也可以改造成和自适应中值一样,不断的扩大半径。

  4、对于同一个半径,这个函数多次迭代效果不会有区别。

  一个简单的实现如下:

    for (int X = 0; X < Width * Channel; X++, LinePD++){int P0 = First[X], P1 = First[X + Channel], P2 = First[X + 2 * Channel];int P3 = Second[X], P4 = Second[X + Channel], P5 = Second[X + 2 * Channel];int P6 = Third[X], P7 = Third[X + Channel], P8 = Third[X + 2 * Channel];int Max0 = IM_Max(P0, P1);int Min0 = IM_Min(P0, P1);int Max1 = IM_Max(P2, P3);int Min1 = IM_Min(P2, P3);int Max2 = IM_Max(P5, P6);int Min2 = IM_Min(P5, P6);int Max3 = IM_Max(P7, P8);int Min3 = IM_Min(P7, P8);int Max = IM_Max(IM_Max(Max0, Max1), IM_Max(Max2, Max3));int Min = IM_Min(IM_Min(Min0, Min1), IM_Min(Min2, Min3));if (P4 > Max)P4 = Max;else if (P4 < Min)P4 = Min;LinePD[0] = P4;}

  因为去除了中心点后进行的最大值和最小计算,这个算法如果要实现高效率的和半径无关的版本,还是需要做一番研究的,目前我尚没有做出成果。

  我们拿标准的Lena图测试,使用matlab分别为他增加0.02及0.2范围的椒盐噪音,然后使用自适应中值滤波及保守滤波进行处理。

    

          添加0.02概率的椒盐噪音图                         最小半径1,最大半径13时的去噪效果                          3*3的保守滤波

    

      添加0.2概率的椒盐噪音图                              最小半径1,最大半径5时的去噪效果                                3*3的保守滤波

  可以看到,自适应中值滤波在去除椒盐噪音的效果简直就是逆天,基本完美的复现了原图,有的时候我自己都不敢相信这个结果。而保守滤波由于目前我只实现了3*3的版本,因此对于噪音比较集中的地方暂时无法去除,这个可以通过扩大半径和类似使用自适应中值的方式处理,而这种噪音的图像使用DCT去噪、小波去噪、NLM等等都不具有很好的效果,唯一能和他比拟的就只有蒙版和划痕里面小参数时的效果(这也是以中值为基础的)。所以去除椒盐噪音还是得靠中值相关的算法啊。

  和常规的中值滤波器相比,自适应中值滤波器能够更好的保护图像中的边缘细节部分,当然代价就是增加了算法的时间复杂度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/826580.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[快速阅读] 自适应中值滤波及保守滤波在去除椒盐噪音或脉冲噪音上的应用。

去除椒盐噪音或脉冲噪音最经典的算法是中值滤波,通常在噪声的密度不是很大的情况下,使用中值效果不错。但当概率较大时,普通中值已经难以胜任,此时自适应中值滤波的处理效果简直就是逆天,基本完美的复现了原图,有的时候我自己都不敢相信这个结果,而保守滤波采用了稍微不…

瑞芯微RK3566开发板OpenHarmony标准系统应用兼容性测试指导

本文OpenHarmony标准系统应用兼容性测试指导,适用鸿蒙系统软件开发测试的新手入门学习课程。设备为触觉智能的瑞芯微RK3566开发板,型号Purple Pi OH。是Laval官方社区主荐的一款鸿蒙开发主板。支持Openharmony、安卓Android、Linux的Debian、Ubuntu系统。本文OpenHarmony标准…

continue调用1.5B小模型实现代码fast-apply

100tok/s生成速度,就问够不够fast?用过cursor的小伙伴一定对有个功能印象深刻,那就是fast apply功能。只要点一下,就可以把对话框中AI生成的代码快速地应用到编辑器的当前代码文件里, 然后下一步就是对比变更,accept或者reject代码块,相比于要手动从对话框复制代码到编辑…

节省50%人工录入时间!免费开源AI工具让法律文件数据提取更高效

法律行业痛点:处理大量的合同、诉讼材料和财务报告等文件是一项繁琐且耗时的工作。这些文件中的表格常包含关键信息,如费用清单、时效统计和条款列表等,手动录入和整理这些数据不仅效率低下,而且容易出错。思通数科的表格识别技术,结合深度学习和计算机视觉,能够自动提取…

10.28 每日总结(软考ing)

今天继续软考,时长2小时。 看看错题吧:

如何区分实例化网格中的每个实例

1)如何区分实例化网格中的每个实例2)项目在模拟器上切换程序后有概率画面冻结3)Unity工程导入团结引擎,GUID会变化,导致引用关系丢失4)Mask在Android平台下渲染异常这是第407篇UWA技术知识分享的推送,精选了UWA社区的热门话题,涵盖了UWA问答、社区帖子等技术知识点,助…

亚马逊-专利投诉系统-批量投诉-开发-流程引擎

系统图如图所示 所需数据直接通过xls导入。 开发过程:导入xls表格自动生成数据模型。 点击生成表单即可自动创建一个前端UI,如第一张图所示。新增,删除,修改,导入,导出,全部功能默认自带OK。方便灵活调整各种字段,新增字段,修改字段。 一个人使用10分钟即可完成。 到此…

el-table高亮

官网上提供了了高亮的方法,如果不管用,就用下面的高亮方法

操作系统的特征

操作系统的特征 ‍ ​​ ‍一、并发 指两个或多个事件在同一时间间隔内发生。这些事件宏观上是同时发生的,但微观上是交替发生的。 常考易混概念一一并行:指两个或多个事件在同一时刻同时发生。 ​​ ‍ 二、共享 ​​ ‍ ——并发与共享的关系 ​​ ‍ 三、虚拟 虚拟是指,把…

操作系统的概念与功能

操作系统的概念与功能 ‍ ​​ ‍操作系统的定义 操作系统 (Operating System, OS)是指控制和管理整个计算机系统的硬件和软件资源,并合理地组织调度计算机的工作和资源的分配;以提供给用户和其他软件方便的接口和环境;它是计算机系统中最基本的系统软件。 ‍ 操作系统的功…

java springboot对接微信小程序和微信支付v3接口

1、controller代码package com.saburo.server.controller.weixin;import cn.dev33.satoken.annotation.SaIgnore; import com.gcode.common.core.R; import com.saburo.server.common.dto.WeiXinUserInfoDto; import com.saburo.server.common.dto.money.PayDto; import com.sa…

可操作度

如上图所示,好的可操作度可以帮助远离奇异点 1. 可操作度: \(m = \sqrt{det(J(q) J(q)^T)}\) 2. 可操作度雅可比:3. 可操作度控制器QP: