OpenCv学习篇——图像中值滤波算法

一.算法原理

简单的说:以一个3*3的模板划过一幅图像,以像素1到像素9的中位数代替像素5的值。这种滤波的比较适合椒盐噪声这种情况。因为椒盐的值无非是0或255.

二.需要知道的几个知识点

1.希尔排序法:

由于要找到9个数中的中位数,所以需要将9个像素进行排序,当然简单的插入排序法也可以进行排序,这里介绍一种希尔排序法。http://www.iqiyi.com/v_19rrhzyejc.html 这是当时本人学习希尔排序看的视频。https://www.cnblogs.com/chengxiao/p/6104371.html这个帖子讲的也是不错的

希尔排序法简单的来说选取一个步长从第一个数开始间隔步长个数选取先进行直接排序,步长不为1的时候不会得到顺序排列的数组只会得到一个更加有序的数组直到步长为1的时候才能得到顺序排列的数组。

uchar Median(uchar n1, uchar n2, uchar n3, uchar n4, uchar n5,uchar n6, uchar n7, uchar n8, uchar n9)
{
 uchar arr[9];
 arr[0] = n1;
 arr[1] = n2;
 arr[2] = n3;
 arr[3] = n4;
 arr[4] = n5;
 arr[5] = n6;
 arr[6] = n7;
 arr[7] = n8;
 arr[8] = n9;
 for (int gap = 9 / 2; gap > 0; gap /= 2)//希尔排序  ,确定分多少个子序列
  for (int i = gap; i < 9; ++i)
   for (int j = i - gap; j >= 0 && arr[j] > arr[j + gap]; j -= gap)
    swap(arr[j], arr[j + gap]);
 return arr[4];//返回中值 
}

如果for循环转不出来,不要犯懒可以跟我一样用笔转一圈。

跟着走一圈这个排序差不多就出来了。

2.椒盐噪声函数

//图像椒盐化 
void salt(Mat &image, int num) 
{      
 if (!image.data) return;//防止传入空图 
 int i, j;
 srand(time(NULL));
 for (int x = 0; x < num; ++x)
 {
  i = rand() % image.rows;
  j = rand() % image.cols;
  image.at(i, j)[0] = 255;
  image.at(i, j)[1] = 255;
  image.at(i, j)[2] = 255;
 }
}  这个函数就是随机在行列里产生255的值入参为一个mat 类图像的变量和究竟要多少椒盐点

三.程序源码

#include
#include
#include
#include  
#include 
using namespace cv;
using namespace std;
//求九个数的中值 
uchar Median(uchar n1, uchar n2, uchar n3, uchar n4, uchar n5,uchar n6, uchar n7, uchar n8, uchar n9)
{
 uchar arr[9];
 arr[0] = n1;
 arr[1] = n2;
 arr[2] = n3;
 arr[3] = n4;
 arr[4] = n5;
 arr[5] = n6;
 arr[6] = n7;
 arr[7] = n8;
 arr[8] = n9;
 for (int gap = 9 / 2; gap > 0; gap /= 2)//希尔排序  ,确定分多少个子序列
  for (int i = gap; i < 9; ++i)
   for (int j = i - gap; j >= 0 && arr[j] > arr[j + gap]; j -= gap)
    swap(arr[j], arr[j + gap]);
 return arr[4];//返回中值 
}

//图像椒盐化 
void salt(Mat &image, int num) 
{      
 if (!image.data) return;//防止传入空图 
 int i, j;
 srand(time(NULL));
 for (int x = 0; x < num; ++x)
 {
  i = rand() % image.rows;
  j = rand() % image.cols;
  image.at(i, j)[0] = 255;
  image.at(i, j)[1] = 255;
  image.at(i, j)[2] = 255;
 }
}

//中值滤波函数 
void MedianFlitering(const Mat &src, Mat &dst)
{
 if (!src.data)
  return;
 Mat _dst(src.size(), src.type());
 for (int i = 0; i
  for (int j = 0; j < src.cols; ++j)
  {
   if ((i - 1) > 0 && (i + 1) < src.rows && (j - 1) > 0 && (j + 1) < src.cols)
   {
    _dst.at(i, j)[0] = Median(src.at(i, j)[0], src.at(i + 1, j + 1)[0],
     src.at(i + 1, j)[0], src.at(i, j + 1)[0], src.at(i + 1, j - 1)[0],
     src.at(i - 1, j + 1)[0], src.at(i - 1, j)[0], src.at(i, j - 1)[0],
     src.at(i - 1, j - 1)[0]);
    _dst.at(i, j)[1] = Median(src.at(i, j)[1], src.at(i + 1, j + 1)[1],
     src.at(i + 1, j)[1], src.at(i, j + 1)[1], src.at(i + 1, j - 1)[1],
     src.at(i - 1, j + 1)[1], src.at(i - 1, j)[1], src.at(i, j - 1)[1],
     src.at(i - 1, j - 1)[1]);
    _dst.at(i, j)[2] = Median(src.at(i, j)[2], src.at(i + 1, j + 1)[2],
     src.at(i + 1, j)[2], src.at(i, j + 1)[2], src.at(i + 1, j - 1)[2],
     src.at(i - 1, j + 1)[2], src.at(i - 1, j)[2], src.at(i, j - 1)[2],
     src.at(i - 1, j - 1)[2]);
   }
   else
    _dst.at(i, j) = src.at(i, j);
  }
 _dst.copyTo(dst);//拷贝 
}


void main()

{
 Mat image = imread("fzh.jpg");

 Mat Salt_Image;
 image.copyTo(Salt_Image);
 salt(Salt_Image, 3000);

 Mat image3, image4;
 MedianFlitering(Salt_Image, image3);
 medianBlur(Salt_Image, image4, 3);
 imshow("原图", image);
 imshow("自定义中值滤波处理后", image3);
 imshow("openCV自带的中值滤波", image4);
 waitKey(); 
}

四.实现效果图


猜你喜欢

转载自blog.csdn.net/fzhykx/article/details/79486400