内容简介:openCV之中值滤波&均值滤波(及代码实现)
在开始我们今天的博客之前,我们需要先了解一下什么是滤波:
首先我们看一下图像滤波的概念。图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。
下图左边是原图右边是噪声图:
消除图像中的噪声成分叫作图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感兴趣的信息经常被噪声淹没。因此一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。
图像滤波的目的有两个:一是抽出对象的特征作为图像识别的特征模式;另一个是为适应图像处理的要求,消除图像数字化时所混入的噪声。
而对滤波处理的要求也有两条:一是不能损坏图像的轮廓及边缘等重要信息;二是使图像清晰视觉效果好。
平滑滤波是低频增强的空间域滤波技术。它的目的有两类:一类是模糊;另一类是消除噪音。
空间域的平滑滤波一般采用简单平均法进行,就是求邻近像元点的平均亮度值。邻域的大小与平滑的效果直接相关,邻域越大平滑的效果越好,但邻域过大,平滑会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需合理选择邻域的大小。
关于滤波器,一种形象的比喻法是:我们可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口放到图像之上,透过这个窗口来看我们得到的图像。
举一个滤波在我们生活中的应用:美颜的磨皮功能。如果将我们脸上坑坑洼洼比作是噪声的话,那么滤波算法就是来取出这些噪声,使我们自拍的皮肤看起来很光滑。
这篇博文会介绍中值滤波以及均值滤波两种算法
一.均值滤波
图片中一个方块区域(一般为3*3)内,中心点的像素为全部点像素值的平均值。均值滤波就是对于整张图片进行以上操作。
我们可以看下图的矩阵进行理解
缺陷:均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很 好地去除噪声点。特别是椒盐噪声
实现代码:
#include "opencv2/imgproc.hpp" #include "opencv2/highgui.hpp" #include<ctime> using namespace cv; using namespace std; //均值滤波 void AverFiltering(const Mat &src,Mat &dst) { if (!src.data) return; //at访问像素点 for (int i = 1; i<src.rows; ++i) for (int j = 1; j < src.cols; ++j) { if ((i - 1 >= 0) && (j - 1) >= 0 && (i + 1)<src.rows && (j + 1)<src.cols) {//边缘不进行处理 dst.at<Vec3b>(i, j)[0] = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i - 1, j - 1)[0] + src.at<Vec3b>(i - 1, j)[0] + src.at<Vec3b>(i, j - 1)[0] + src.at<Vec3b>(i - 1, j + 1)[0] + src.at<Vec3b>(i + 1, j - 1)[0] + src.at<Vec3b>(i + 1, j + 1)[0] + src.at<Vec3b>(i, j + 1)[0] + src.at<Vec3b>(i + 1, j)[0]) / 9; dst.at<Vec3b>(i, j)[1] = (src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i - 1, j - 1)[1] + src.at<Vec3b>(i - 1, j)[1] + src.at<Vec3b>(i, j - 1)[1] + src.at<Vec3b>(i - 1, j + 1)[1] + src.at<Vec3b>(i + 1, j - 1)[1] + src.at<Vec3b>(i + 1, j + 1)[1] + src.at<Vec3b>(i, j + 1)[1] + src.at<Vec3b>(i + 1, j)[1]) / 9; dst.at<Vec3b>(i, j)[2] = (src.at<Vec3b>(i, j)[2] + src.at<Vec3b>(i - 1, j - 1)[2] + src.at<Vec3b>(i - 1, j)[2] + src.at<Vec3b>(i, j - 1)[2] + src.at<Vec3b>(i - 1, j + 1)[2] + src.at<Vec3b>(i + 1, j - 1)[2] + src.at<Vec3b>(i + 1, j + 1)[2] + src.at<Vec3b>(i, j + 1)[2] + src.at<Vec3b>(i + 1, j)[2]) / 9; } else {//边缘赋值 dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0]; dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1]; dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2]; } } } //图像椒盐化 void salt(Mat ℑ, 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<Vec3b>(i, j)[0] = 255; image.at<Vec3b>(i, j)[1] = 255; image.at<Vec3b>(i, j)[2] = 255; } } void main() { Mat image = imread("路飞.jpg"); Mat Salt_Image; image.copyTo(Salt_Image); salt(Salt_Image, 3000); Mat image1(image.size(), image.type()); Mat image2; AverFiltering(Salt_Image, image1); blur(Salt_Image, image2, Size(3, 3));//openCV库自带的均值滤波函数 imshow("原图", image); imshow("自定义均值滤波", image1); imshow("openCV自带的均值滤波", image2); waitKey(); }
效果图:
可以看到图片变模糊而且噪声并没有很有效的去除,该算法只是模糊化了图片而已。
二.中值滤波
首先,我们复习中值。在一连串数字{1,4,6,8,9}中,数字6就是这串数字的中值。由此我们可以应用到图像处理中。依然我们在图像中去3*3的矩阵,里面有9个像素点,我们将9个像素进行排序,最后将这个矩阵的中心点赋值为这九个像素的中值。
代码:
//求九个数的中值 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 ℑ, 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<Vec3b>(i, j)[0] = 255; image.at<Vec3b>(i, j)[1] = 255; image.at<Vec3b>(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<src.rows;++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<Vec3b>(i, j)[0] = Median(src.at<Vec3b>(i, j)[0], src.at<Vec3b>(i + 1, j + 1)[0], src.at<Vec3b>(i + 1, j)[0], src.at<Vec3b>(i, j + 1)[0], src.at<Vec3b>(i + 1, j - 1)[0], src.at<Vec3b>(i - 1, j + 1)[0], src.at<Vec3b>(i - 1, j)[0], src.at<Vec3b>(i, j - 1)[0], src.at<Vec3b>(i - 1, j - 1)[0]); _dst.at<Vec3b>(i, j)[1] = Median(src.at<Vec3b>(i, j)[1], src.at<Vec3b>(i + 1, j + 1)[1], src.at<Vec3b>(i + 1, j)[1], src.at<Vec3b>(i, j + 1)[1], src.at<Vec3b>(i + 1, j - 1)[1], src.at<Vec3b>(i - 1, j + 1)[1], src.at<Vec3b>(i - 1, j)[1], src.at<Vec3b>(i, j - 1)[1], src.at<Vec3b>(i - 1, j - 1)[1]); _dst.at<Vec3b>(i, j)[2] = Median(src.at<Vec3b>(i, j)[2], src.at<Vec3b>(i + 1, j + 1)[2], src.at<Vec3b>(i + 1, j)[2], src.at<Vec3b>(i, j + 1)[2], src.at<Vec3b>(i + 1, j - 1)[2], src.at<Vec3b>(i - 1, j + 1)[2], src.at<Vec3b>(i - 1, j)[2], src.at<Vec3b>(i, j - 1)[2], src.at<Vec3b>(i - 1, j - 1)[2]); } else _dst.at<Vec3b>(i, j) = src.at<Vec3b>(i, j); } _dst.copyTo(dst);//拷贝 } void main() { Mat image = imread("路飞.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("自定义中值滤波处理后", image3); imshow("openCV自带的中值滤波", image4); waitKey(); }
效果图:
可以看到,椒盐噪声很好的被平滑了,而且也没均值那样模糊化太过于严重。
以上所述就是小编给大家介绍的《openCV之中值滤波&均值滤波(及代码实现)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- C++ 实现 CVPR 2019 side window 中值滤波
- 粒子滤波Matlab示例
- 粒子滤波Matlab示例
- OpenCV 线性滤波
- 【信号与系统】05 - 滤波、采样和通信
- 使用matlab进行傅里叶分析和滤波
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
编程原本
Alexander Stepanov、Paul McJones / 裘宗燕 / 机械工业出版社华章公司 / 2012-1-10 / 59.00元
本书提供了有关编程的一种与众不同的理解。其主旨是,实际的编程也应像其他科学和工程领域一样基于坚实的数学基础。本书展示了在实际编程语言(如C++)中实现的算法如何在最一般的数学背景中操作。例如,如何定义快速求幂算法,使之能使用任何可交换运算。使用抽象算法将能得到更高效、可靠、安全和经济的软件。 这不是一本很容易读的书,它也不是能提升你的编程技能的秘诀和技巧汇编。本书的价值是更根本性的,其终极目......一起来看看 《编程原本》 这本书的介绍吧!