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

  本文参考博客: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*3的半径为1,中值百分比)
function grayimg=medianfilterhuang(grayimg,radius,percentage)
    [sizex,sizey]=size(grayimg);
    thres=int16(((2*radius+1)^2*percentage));
    %扩展边界
    extendimg=int16(horzcat(repmat(grayimg(:,1),1,radius),grayimg,repmat(grayimg(:,sizey),1,radius)));
    extendimg=int16(vertcat(repmat(extendimg(1,:),radius,1),extendimg,repmat(extendimg(sizex,:),radius,1)));
    for i=radius+1:sizex+radius
        %初始化直方图,每行第一个将所有像素加入直方图
        histogram=int16(zeros(256,1));
        sumcnt=int16(0);
        median=int16(0);
        for j=radius+1:sizey+radius
            %遍历卷积覆盖行
            for k=i-radius:i+radius
                if (j>radius+1)
                    %删去左列,加入新右列
                    histogram(extendimg(k,j-radius-1)+1)=histogram(extendimg(k,j-radius-1)+1)-1;
                    histogram(extendimg(k,j+radius)+1)=histogram(extendimg(k,j+radius)+1)+1;
                    %只关心中值灰度以左的像素数量
                    if (extendimg(k,j-radius-1)<median)
                        sumcnt=sumcnt-1;
                    end
                    if (extendimg(k,j+radius)<median)
                        sumcnt=sumcnt+1;
                    end
                else
                    %行首
                    for h=j-radius:j+radius
                        histogram(extendimg(k,h)+1)=histogram(extendimg(k,h)+1)+1;
                    end
                end
            end
            %sumcnt不将中值像素数累加进去
            %旧中值偏大
            while(sumcnt>=thres)
                median=median-1;
                sumcnt=sumcnt-histogram(median+1);
            end
            %旧中值偏小
            while(sumcnt+histogram(median+1)<thres)
                sumcnt=sumcnt+histogram(median+1);
                median=median+1;
            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(((2*radius+1)^2*percentage));
    %扩展边界
    extendimg=int16(horzcat(repmat(grayimg(:,1),1,radius),grayimg,repmat(grayimg(:,sizey),1,radius)));
    extendimg=int16(vertcat(repmat(extendimg(1,:),radius+1,1),extendimg,repmat(extendimg(sizex,:),radius,1)));
    %为每一列维护一个全位直方图和一个高位直方图
    histogram_cols_low=int16(zeros(sizey+2*radius,256));
    histogram_cols_high=int16(zeros(sizey+2*radius,16));
    %中值计算所用的一个全位直方图和一个高位直方图
    histogram_low=int16(zeros(1,256));
    histogram_high=int16(zeros(1,16));
    %全位转高位的加速索引
    grayrange=int16(zeros(1,256));
    for i=1:16
        grayrange(:,(i-1)*16+1:i*16)=i;
    end
    %初始化各列直方图
    for row=1:2*radius+1
        for col=1:sizey+2*radius
            histogram_cols_low(col,extendimg(row,col)+1)=histogram_cols_low(col,extendimg(row,col)+1)+1;
            histogram_cols_high(col,grayrange(extendimg(row,col)+1))=histogram_cols_high(col,grayrange(extendimg(row,col)+1))+1;
        end
    end

    for row=int16(radius+2:sizex+radius+1)
        for col=int16(radius+1:sizey+radius)
            if(col>radius+1)
                %更新右边新列,删除左边旧列
                histogram_cols_low(col+radius,extendimg(row+radius,col+radius)+1)=histogram_cols_low(col+radius,extendimg(row+radius,col+radius)+1)+1;
                histogram_cols_low(col+radius,extendimg(row-radius-1,col+radius)+1)=histogram_cols_low(col+radius,extendimg(row-radius-1,col+radius)+1)-1;
                histogram_cols_high(col+radius,grayrange(extendimg(row+radius,col+radius)+1))=histogram_cols_high(col+radius,grayrange(extendimg(row+radius,col+radius)+1))+1;
                histogram_cols_high(col+radius,grayrange(extendimg(row-radius-1,col+radius)+1))=histogram_cols_high(col+radius,grayrange(extendimg(row-radius-1,col+radius)+1))-1;
                histogram_low=histogram_low+histogram_cols_low(col+radius,:)-histogram_cols_low(col-radius-1,:);
                histogram_high=histogram_high+histogram_cols_high(col+radius,:)-histogram_cols_high(col-radius-1,:);
            else
                histogram_low(:,:)=0;
                histogram_high(:,:)=0;
                %行首手动初始化各列
                for index=1:2*radius+1
                    histogram_cols_low(index,extendimg(row+radius,index)+1)=histogram_cols_low(index,extendimg(row+radius,index)+1)+1;
                    histogram_cols_low(index,extendimg(row-radius-1,index)+1)=histogram_cols_low(index,extendimg(row-radius-1,index)+1)-1;
                    histogram_cols_high(index,grayrange(extendimg(row+radius,index)+1))=histogram_cols_high(index,grayrange(extendimg(row+radius,index)+1))+1;
                    histogram_cols_high(index,grayrange(extendimg(row-radius-1,index)+1))=histogram_cols_high(index,grayrange(extendimg(row-radius-1,index)+1))-1;
                    histogram_low=histogram_low+histogram_cols_low(index,:);
                    histogram_high=histogram_high+histogram_cols_high(index,:);
                end
            end
            %中值及之前的所有像素数
            sumcnt=int16(0);
            for gray_high=1:16
                sumcnt=sumcnt+histogram_high(gray_high);
                if (sumcnt>=thres)
                    break;
                end
            end

            for gray_low=gray_high*16:-1:(gray_high-1)*16+1
                sumcnt=sumcnt-histogram_low(gray_low);
                if (sumcnt<thres)
                    break;
                end
            end

            grayimg(row-radius-1,col-radius)=gray_low-1;
        end
    end

end

O(1)中值滤波

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

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

              

原文地址:https://www.cnblogs.com/kensporger/p/11660984.html

时间: 2024-10-19 02:25:39

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

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

终于搞出来了:) #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必须是单通

VC++高斯滤波\中值滤波实现图像模糊处理

一.算法 高斯模糊算法 详见:高斯模糊,基本思想就是利用高斯函数,将一个坐标点的所有邻域的加权平均值设置为这些点的颜色值. 中值滤波算法就更简单了:将一个坐标点的所有邻域的平均值设置为这些点的像素值. 二.算法的代码实现 高斯函数: 使用宏定义来替换: #define PI<span style="white-space:pre"> </span>3.1415926 //高斯模糊函数 #define GAUSS_FUN(x, y) (exp(-(x*x)/(do

自适应中值滤波(基于C++和OpenCV)Kinect深度图

<span style="font-family:Microsoft YaHei;font-size:14px;">#include <opencv2/opencv.hpp> #include <vector> #define uint unsigned int using namespace cv; const uint rowNumber = 480; const uint colNumber = 640; void AutoMedianFilt

中值滤波与图像锐化

本文主要包括以下内容 中值滤波及其改进算法 图像锐化, 包括梯度算子.拉普拉斯算子.高提升滤波和高斯-拉普拉斯变换 本章的典型囊例分析 对椒盐噪声的平滑效果比较 Laplacian与LoG算子的锐化效果比较 中值滤波 中值滤波本质上是一种统计排序滤波器. 对于原图像中某点(i,j), 中值滤波以该点为中 心的邻域内的所有像素的统计排序中值作为(i, j) 点的响应. 中值不同于均值, 是指排序队列中位于中间位置的元素的值,例如=采用3x3 中值滤披 器, 某点.(i,j) 的8 个邻域的一系列像

数字图像处理------中值滤波

一 中值滤波概念 中值滤波算法以某像素的领域图像区域中的像素值的排序为基础,将像素领域内灰度的中值代替该像素的值[1]: 如:以3*3的领域为例求中值滤波中像素5的值 图1 1)int pixel[9]中存储像素1,像素2...像素9的值: 2)对数组pixel[9]进行排序操作: 3)像素5的值即为数组pixel[9]的中值pixel[4]. 中值滤波对处理椒盐噪声非常有效. 二 中值滤波代码实现 项目工程:https://github.com/ranjiewwen/Everyday_Prac

均值滤波,中值滤波,最大最小值滤波

http://blog.csdn.net/fastbox/article/details/7984721 讨论如何使用卷积作为数学工具来处理图像,实现图像的滤波,其方法包含以下几种,均值 滤波,中值滤波,最大最小值滤波,关于什么是卷积以及理解卷积在图像处理中作用参见这 里–http://blog.csdn.net/jia20003/article/details/7038938 均值滤波: 均值滤波,是图像处理中最常用的手段,从频率域观点来看均值滤波是一种低通滤波器,高 频信号将会去掉,因此可以

中值滤波的快速算法

我想学过图像处理的人没有人会不知道中值滤波的,最早的时候我是在冈萨雷斯的图像处理课本[1]中学到的,后来在看Sonka的书[2]的时候又看到了中值滤波的介绍,下面我试着结合课本所学和网上的资料自己整理一篇中值滤波的介绍. Jeremy Lin 中值滤波器是一种统计排序滤波器,由Tukey于1971年在文献[3]中提出.所谓的统计排序滤波器是一种非线性的空间滤波器,它的响应基于图像滤波器包围的图像区域中像素的排序,然后用统计排序结果决定的值代替中心像素的值.除了中值滤波器外,最大值滤波器和最小值滤

图像平滑技术之盒滤波、均值滤波、中值滤波、高斯滤波、双边滤波的原理概要及OpenCV代码实现

图像平滑是指直接对源图像的每个像素数据做邻域运算以达到平滑图像的目的.实质上主要就是通达卷积核算子实现的,卷积核算子的相关知识大家可以参考我写的博文http://blog.csdn.net/wenhao_ir/article/details/51691410 图像平滑也称为模糊或滤波,是图像处理中常用的技术之一,进行平滑处理时需要用到滤波器核(其实就是卷积核算子),根据滤波器核函数来实现不同的滤波技术.下面介绍几种 常用的图像平滑方法的大概原理及OpenCV下的实现代码. 一.盒滤波(均值滤波)

实时高速实现改进型中值滤波算法_爱学术_免费下载

[摘要]在图像采集和处理过程中会引入噪声,必须先对图像进行预处理.本文介绍一种快速中值滤波算法,该算法在硬件平台上实现实时处理功能.综合考虑,选择现场可编程门阵列(FPGA)作为硬件平台,采用硬件描述语言Verilog实现改进型中值滤波算法.经Modelsim仿真结果表明:基于FPGA硬件平台实现改进型中值滤波算法不仅速度快,而且实时处理效果佳,提高了图像处理的效率. [作者] 杨晶  王元庆 转载至爱学术:https://www.ixueshu.com/document/29bcda14996