本文参考博客:https://www.cnblogs.com/Imageshop/archive/2013/04/26/3045672.html

  原生的中值滤波是基于排序算法的,这样的算法复杂度基本在O(r2)左右,当滤波半径较大时,排序算法就显得很慢。对此有多种改进算法,这里介绍经典

的Huang算法与O(1)算法,两者都是基于记忆性的算法,只是后者记性更强。

  排序算法明显的一个不足之处就是无记忆性。当核向右移动一列后,只是核的最左和最右列数据发生了变化,中间不变的数据应当被存储起来,而排序算法

并没有做到这点。Huang算法的思想是建立一个核直方图,来统计核内的各灰度的像素数。当核向右移动时,就将新的一列所有数据加入到直方图中,同时将最

左列的旧数据从直方图中删除,如下图所示。这样做使得大部分数据能够被记忆,减少重复操作。当直方图更新完毕后,就可以通过从左到右累计像素来找到中值。

              

下面是算法具体实现步骤与代码:

  1.每行开始都将直方图、像素计数、中值变量清零,将核覆盖的所有像素加到直方图中。

  2.计算中值,sumcnt为小于中值灰度的像素数和。如果当前sumcnt大于等于阈值,则表明,实际中值比当前median小,则直方图向左减去像素数,同时median

   也减小,直到sumcnt小于阈值,则此时median为中值(sumcnt加上中值像素数将大于或等于阈值);如果sumcnt加上median像素数仍小于阈值,表明,实

   际中值比当前median大,则直方图向右累加像素数,同时median增加,直到sumcnt加上median像素数大于等于阈值,则此时median为中值(sumcnt小于阈值)。

  3.核每向右移动一列,更新核直方图,比较每一个新加入的灰度值与median,小于则median加1,比较每一个减去的灰度值与median,小于则median减1。执行

   一次步骤2后继续移动核,直到整幅图都被滤波完毕。

%中值滤波黄法
%输入:8位深度图像、滤波半径(*3的半径为1,中值百分比)
function grayimg=medianfilterhuang(grayimg,radius,percentage)
[sizex,sizey]=size(grayimg);
thres=int16(((*radius+)^*percentage));
%扩展边界
extendimg=int16(horzcat(repmat(grayimg(:,),,radius),grayimg,repmat(grayimg(:,sizey),,radius)));
extendimg=int16(vertcat(repmat(extendimg(,:),radius,),extendimg,repmat(extendimg(sizex,:),radius,)));
for i=radius+:sizex+radius
%初始化直方图,每行第一个将所有像素加入直方图
histogram=int16(zeros(,));
sumcnt=int16();
median=int16();
for j=radius+:sizey+radius
%遍历卷积覆盖行
for k=i-radius:i+radius
if (j>radius+)
%删去左列,加入新右列
histogram(extendimg(k,j-radius-)+)=histogram(extendimg(k,j-radius-)+)-;
histogram(extendimg(k,j+radius)+)=histogram(extendimg(k,j+radius)+)+;
%只关心中值灰度以左的像素数量
if (extendimg(k,j-radius-)<median)
sumcnt=sumcnt-;
end
if (extendimg(k,j+radius)<median)
sumcnt=sumcnt+;
end
else
%行首
for h=j-radius:j+radius
histogram(extendimg(k,h)+)=histogram(extendimg(k,h)+)+;
end
end
end
%sumcnt不将中值像素数累加进去
%旧中值偏大
while(sumcnt>=thres)
median=median-;
sumcnt=sumcnt-histogram(median+);
end
%旧中值偏小
while(sumcnt+histogram(median+)<thres)
sumcnt=sumcnt+histogram(median+);
median=median+;
end
grayimg(i-radius,j-radius)=median;
end
end
end

Huang算法

  性能分析发现,Huang算法的大部分时间花在了更新核直方图上。并且由于它是O(r)的复杂度,因此当滤波半径变大后,更新直方图部分花费的时间也变多,而计算

中值部分所花时间一直都是固定的,因为它的复杂度是O(1),与滤波半径无关。那么为了使直方图更新的复杂度能降到O(1),就要增强算法的记忆性。可以看到以相邻行

相同列为中心的核之间也存在重合,这跟之前以相邻列相同行为中心的核存在重合类似。于是,我们可以为每列都维护一个直方图,而核直方图可以由这些列直方图相加

得到,更新核的时候,最右边的一列直方图向下移动一行,就更新了列直方图,再减去最左边一列直方图,核就得到更新。这样每次更新直方图都只要移动一次列直方图,

而其余的都是直方图的加减操作,值得注意的是,这样的实现很完美得利用了可并行的矩阵加减来代替顺序执行的for迭代。因此,虽然更新过程看上去有许多加减操作,

实际上都是可快速并行执行的。

        

  还有一点,由于并行化的矩阵加减,就不能用sumcnt来跟踪阈值变化了。如果直接迭代累加直方图,最坏的情况是要执行255加法。为了使中值计算更快,可以采用

两层直方图,高层用于保存高4位(直方图大小为16*1),低层保存全位(直方图大小为256*1)。每次先累加高层进行范围缩小,再从相应范围累加低层找到中值。只是

这样就牺牲了内存空间。

下面是算法具体实现步骤与代码:

  1.扩展图像边界,上边界扩展r+1行,其他边界扩展r行;为每列生成两层直方图,并为其初始化,添加各列的前2*r+1个像素;生成一个低层链接高层的索引矩阵。

  2.每行开始清零核直方图,更新核覆盖的各列直方图(向下移动一行),将各列加到核直方图中。

  3.寻找中值,初始化sumcnt=0,这里它表示小于等于中值灰度的像素和,从左到右迭代高层直方图,直到sumcnt大于等于阈值;再从高层确定的范围内从右到左迭代

   低层直方图,直到sumcnt(减去了迭代灰度的像素数)小于阈值,则当前迭代值为中值。

  4.核每向右移动,更新列直方图与核直方图,执行一次步骤3,然后继续移动核,直到完成整个图的滤波。

function grayimg=medianfilterdp(grayimg,radius,percentage)
[sizex,sizey]=size(grayimg);
thres=int16(((*radius+)^*percentage));
%扩展边界
extendimg=int16(horzcat(repmat(grayimg(:,),,radius),grayimg,repmat(grayimg(:,sizey),,radius)));
extendimg=int16(vertcat(repmat(extendimg(,:),radius+,),extendimg,repmat(extendimg(sizex,:),radius,)));
%为每一列维护一个全位直方图和一个高位直方图
histogram_cols_low=int16(zeros(sizey+*radius,));
histogram_cols_high=int16(zeros(sizey+*radius,));
%中值计算所用的一个全位直方图和一个高位直方图
histogram_low=int16(zeros(,));
histogram_high=int16(zeros(,));
%全位转高位的加速索引
grayrange=int16(zeros(,));
for i=:
grayrange(:,(i-)*+:i*)=i;
end
%初始化各列直方图
for row=:*radius+
for col=:sizey+*radius
histogram_cols_low(col,extendimg(row,col)+)=histogram_cols_low(col,extendimg(row,col)+)+;
histogram_cols_high(col,grayrange(extendimg(row,col)+))=histogram_cols_high(col,grayrange(extendimg(row,col)+))+;
end
end for row=int16(radius+:sizex+radius+)
for col=int16(radius+:sizey+radius)
if(col>radius+)
%更新右边新列,删除左边旧列
histogram_cols_low(col+radius,extendimg(row+radius,col+radius)+)=histogram_cols_low(col+radius,extendimg(row+radius,col+radius)+)+;
histogram_cols_low(col+radius,extendimg(row-radius-,col+radius)+)=histogram_cols_low(col+radius,extendimg(row-radius-,col+radius)+)-;
histogram_cols_high(col+radius,grayrange(extendimg(row+radius,col+radius)+))=histogram_cols_high(col+radius,grayrange(extendimg(row+radius,col+radius)+))+;
histogram_cols_high(col+radius,grayrange(extendimg(row-radius-,col+radius)+))=histogram_cols_high(col+radius,grayrange(extendimg(row-radius-,col+radius)+))-;
histogram_low=histogram_low+histogram_cols_low(col+radius,:)-histogram_cols_low(col-radius-,:);
histogram_high=histogram_high+histogram_cols_high(col+radius,:)-histogram_cols_high(col-radius-,:);
else
histogram_low(:,:)=;
histogram_high(:,:)=;
%行首手动初始化各列
for index=:*radius+
histogram_cols_low(index,extendimg(row+radius,index)+)=histogram_cols_low(index,extendimg(row+radius,index)+)+;
histogram_cols_low(index,extendimg(row-radius-,index)+)=histogram_cols_low(index,extendimg(row-radius-,index)+)-;
histogram_cols_high(index,grayrange(extendimg(row+radius,index)+))=histogram_cols_high(index,grayrange(extendimg(row+radius,index)+))+;
histogram_cols_high(index,grayrange(extendimg(row-radius-,index)+))=histogram_cols_high(index,grayrange(extendimg(row-radius-,index)+))-;
histogram_low=histogram_low+histogram_cols_low(index,:);
histogram_high=histogram_high+histogram_cols_high(index,:);
end
end
%中值及之前的所有像素数
sumcnt=int16();
for gray_high=:
sumcnt=sumcnt+histogram_high(gray_high);
if (sumcnt>=thres)
break;
end
end for gray_low=gray_high*:-:(gray_high-)*+
sumcnt=sumcnt-histogram_low(gray_low);
if (sumcnt<thres)
break;
end
end grayimg(row-radius-,col-radius)=gray_low-;
end
end end

O(1)中值滤波

  下面是两种算法的性能对比,可以发现,在滤波半径较小的时候,用Huang算法更好;当滤波半径>=8时,用后一种算法更快。实际中我们一般用不到大半径,但这两种

算法的思想很不错,尤其是第二种的空间换时间,我们可能可以发现横向存在重复性,但很容易忽略了纵向上的重复性。

              

基于记忆性的中值滤波O(r)与O(1)复杂度的算法实现的更多相关文章

  1. 基于Opencv的自适应中值滤波函数selfAdaptiveMedianBlur()

    7.3.3 自适应滤波器 自适应中值滤波器 对于7.3.2节所讨论的中值滤波器,只要脉冲噪声的空间密度不大,性能还是可以的(根据经验需Pa和Pb小于0.2).本节将证明,自适应中值滤波器可以处理更大概 ...

  2. verilog实现中值滤波

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

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

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

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

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

  5. 基于MATLAB的中值滤波均值滤波以及高斯滤波的实现

    基于MATLAB的中值滤波均值滤波以及高斯滤波的实现 作者:lee神 1.   背景知识 中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值. 中值滤 ...

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

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

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

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

  8. 学习 opencv---(8)非线性滤波:中值滤波,双边滤波

    正如我们上一篇文章中讲到的,线性滤波可以实现很多种不同的图像变换.然而非线性滤波,如中值滤波器和双边滤波器,有时可以达到更好的实现效果. 邻域算子的其他一些例子还有对 二值图像进行操作的形态学算子,用 ...

  9. verilog 实现中值滤波

    图像信号在形成.传输和记录的过程中,由于成像系统.传输介质.工作环境和记录设备等的固有缺陷,不可避免地产生各种类型的噪声,降低了图像的质量,进而影响后续处理(如边缘检测.图像分割.特征提取.模式识别等 ...

随机推荐

  1. MongoDB安装调试

    1:安装 去mongodb的官网http://www.mongodb.org/downloads下载32bit的包 解压后会出现以下文件 在安装的盘C:下建立mongodb文件夹,拷贝bin文件夹到该 ...

  2. Python的 Datetime 、 Logging 模块

    Datetime模块 datetime是python处理时间和日期的标准库 类名 date类        日期对象,常用的属性有 year . month . day time类        时间 ...

  3. 让Windows的文件名区分大小写

    背景 最近在Linux官网下载了Linux内核,下载下来的是一个后缀为.tar.xz的压缩包,于是在毫不知情的情况下随随便便解压了,解压过程中出现了很多问题. 其中一个问题就是在Windows下,不区 ...

  4. Linux同一机器设置多个IP2019-7-6

    1.临时增加 1)先查看目前的网卡信息 [root@study ~]# ifconfigeno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAS ...

  5. 不能聚焦元素问题 WebDriverException: Message: unknown error: cannot focus element

    上周碰到了 Unable to locate element,即“无法定位元素”,后靠两行代码解决: wait = ui.WebDriverWait(driver,5) wait.until(lamb ...

  6. Maven配置以及环境搭配

    1. Maven简单介绍 Apache Maven是个项目管理和自动构建工具,基于项目对象模型(POM)的概念. 作用:完成项目的相关操作,如:编译,构建,单元测试,安装,网站生成和基于Maven部署 ...

  7. 1. Go语言—初始

    一.golang语言特性 1. 垃圾回收 内存自动回收,再也不需要开发人员管理内存 开发人员专注业务实现,降低了心智负担 只需要new分配内存,不需要释放 2. 天然并发 从语言层面支持并发,非常简单 ...

  8. drf扩展知识点总结视图

  9. (day50)二、文件配置、ORM

    目录 一.静态文件 (一)配置html文件 (二)什么是静态文件 (三)静态文件配置 (四)静态文件动态绑定 (五)form表单POST请求配置 二.request方法初识 (一)request.me ...

  10. 浅谈C++ STL queue 容器

    浅谈C++ STL queue 容器 本篇随笔简单介绍一下\(C++STL\)中\(queue\)容器的使用方法和常见的使用技巧.\(queue\)容器是\(C++STL\)的一种比较基本的容器.我们 ...