zoukankan      html  css  js  c++  java
  • 图像处理——(源)中值滤波(MediFilter)函数编程实现

    https://blog.csdn.net/tengfei461807914/article/details/83626123

    中值滤波是一种非线性滤波,在处理脉冲噪声以及椒盐噪声时效果极佳,能够有效的保护好图像的边缘信息。

    中值滤波的处理思路很简单,取卷积核当中所覆盖像素中的中值作为锚点的像素值即可。

    如果按照遍历所有像素,再对卷积核中的像素排序取中值,那么时间复杂度会很高,需要对中值滤波进行改进。

    中值滤波的改进实际上很是很好想的,无非就是一个滑动窗口取中值的问题,每次向右滑动的过程中等于在窗口中新添加添加一列窗口像素,同时减去一列窗口像素,考虑维护这个窗口中的像素信息变化即可。

    这里面使用huang算法,该思路是这个人提出来的,算法思路如下:

    在计算中值的办法中,不使用排序,而是使用像素直方图,也就是记录像素值的哈希。首先设定阈值threshold,这个threshold就是窗口的中心位置,即ksize×ksize/2+1,kisze为窗口尺寸。

    每次在计算中值的过程中,从小到大累加像素直方图的值,如果该值大于等于,此时对应的像素值就是中值了。

    例如ksize=3的窗口如下:
    ⎡⎣⎢122235154⎤⎦⎥(3) left[egin{matrix}1 & 2 & 1 \2 & 3 & 5 \2 & 5 & 4end{matrix} ight] ag{3}




    1
    2
    2


    2
    3
    5


    1
    5
    4





    (3)

    对该窗口中的值计算像素直方图如下,threshold=3×3/2+1=5
    1:2(表示像素值为1的有2个)
    2:3
    3:1
    4:1
    5:2

    因为2+3≥5,所以中值为2

    每次滑动窗口的过程中,如果窗口在第一列,那么直接计算直方图。否则向右移动,在直方图中减去左侧离开窗口中像素,在右侧添加进入窗口中的像素。

    此外,也可以让窗口按照蛇形来移动,这样也会避免每次窗口在第一列时需要重新计算的问题。

      1 void AddSultPapperNoise(const Mat &src, Mat &dst,int num)//添加椒盐噪声
      2 {
      3     dst = src.clone();
      4     uchar *pd=dst.data;
      5     int row, col, cha;
      6     srand((unsigned)time(NULL));
      7     while (num--)
      8     {
      9         row = rand() % dst.rows;
     10         col = rand() % dst.cols;
     11         cha = rand() % dst.channels();
     12         pd[(row*dst.cols + col)*dst.channels() + cha] = 0;
     13     }
     14 }
     15 
     16 
     17 int GetMediValue(const int histogram[], int thresh)//计算中值
     18 {
     19     int sum = 0;
     20     for (int i = 0; i < (1 << 16); i++)
     21     {
     22         sum += histogram[i];
     23         if (sum >= thresh)
     24             return i;
     25     }
     26     return (1 << 16);
     27 }
     28 
     29 void MyFastMediFilter(const Mat &src, Mat &dst, int ksize)
     30 {
     31     CV_Assert(ksize % 2 == 1);
     32 
     33     Mat tmp;
     34     int len = ksize / 2;
     35     tmp.create(Size(src.cols + len, src.rows + len), src.type());//添加边框
     36     dst.create(Size(src.cols, src.rows), src.type());
     37 
     38 
     39     int channel = src.channels();
     40     uchar *ps = src.data;
     41     uchar *pt = tmp.data;
     42     for (int row = 0; row < tmp.rows; row++)//添加边框的过程
     43     {
     44         for (int col = 0; col < tmp.cols; col++)
     45         {
     46             for (int c = 0; c < channel; c++)
     47             {
     48                 if (row >= len && row < tmp.rows - len && col >= len && col < tmp.cols - len)
     49                     pt[(tmp.cols * row + col) * channel + c] = ps[(src.cols * (row - len) + col - len) * channel + c];
     50                 else
     51                     pt[(tmp.cols * row + col) * channel + c] = 0;
     52             }
     53         }
     54     }
     55     int Hist[(1 << 16)] = { 0 };
     56     uchar *pd = dst.data;
     57     ushort val = 0;
     58     pt = tmp.data;
     59     for (int c = 0; c < channel; c++)//每个通道单独计算
     60     {
     61         for (int row = len; row < tmp.rows - len; row++)
     62         {
     63             for (int col = len; col < tmp.cols - len; col++)
     64             {
     65                 
     66                 if (col == len)
     67                 {
     68                     memset(Hist, 0, sizeof(Hist));
     69                     for (int x = -len; x <= len; x++)
     70                     {
     71                         for (int y = -len; y <= len; y++)
     72                         {
     73                             val = pt[((row + x) * tmp.cols + col + y) * channel + c];
     74                             Hist[val]++;
     75                         }
     76                     }
     77                 }
     78                 else
     79                 {
     80                     int L = col - len - 1;
     81                     int R = col + len;
     82                     for (int y = -len; y <= len; y++)
     83                     {
     84                         int leftInd = ((row + y) * tmp.cols + L) * channel + c;
     85                         int rightInd = ((row + y) * tmp.cols + R) * channel + c;
     86                         Hist[pt[leftInd]]--;
     87                         Hist[pt[rightInd]]++;
     88                     }
     89                 }
     90                 val = GetMediValue(Hist, ksize*ksize / 2 + 1);
     91                 pd[(dst.cols * (row - len) + col - len) * channel + c] = val;
     92                 
     93             }
     94         }
     95     }
     96 }
     97 
    萍水相逢逢萍水,浮萍之水水浮萍!
  • 相关阅读:
    Android实现资料收藏
    GPS(Global Positioning System)全球定位系统
    Android开发环境搭建全程演示(jdk+eclipse+android sdk)
    ADT在线安装
    简洁判断一个byte中有多少位为1的bit?
    tomcat部署java项目
    centos7把编译安装的服务通过systemctl管理
    ansible自动化部署
    redi通过哨兵sentinel实现主从切换
    redis实现集群加主从复制
  • 原文地址:https://www.cnblogs.com/AIBigTruth/p/11183476.html
Copyright © 2011-2022 走看看