滤波器是信号和图像处理的最基础的处理。用于删除噪声,突出感兴趣的区域,允许图像重采样等等。滤波是在信号与系统原理中发现的,比较重要的概念就是频域,高频是指变化比较快的像素,低频是变化相对慢的像素。例如一个图像中,变化微弱的蓝天白云就是低频,而拥挤的街道,还有很多小物体,颜色变化复杂,就属于高频。因此,对图像的频域处理是不同于空域的另一种处理方法。
频域分析将图像分解为从低频到高频分布,低频表示强度变化缓慢,高频表示强度变化快。有很多常见的变换方法,比如傅里叶变换,余弦变换。图像是二维的,所以包括垂直和水平的频域。
频域分析作用于图像上就是增强一部分频带和减弱一部分频带,比如低频滤波器消除高频带,相对应的,高频滤波器消除低频带。具体滤波器的处理实际作用在下面将讨论。
在这一节中,我们将介绍一些基本的低频滤波器。从上面的介绍,我们知道这样的滤波器作用是减少图像像素的振幅变化。一个简单的实现方法是将像素用相邻像素的平均值代替,通过这种处理,变化快的像素将被过渡像素代替,而变得平滑。
opencv中提供了函数cv::blur,是将像素用以像素为中心的矩形内的相邻像素平均值代替来平滑图像。
函数头文件:#include <opencv2/imgproc/imgproc.hpp>
函数定义:
CV_EXPORTS_W void blur( InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT );例子:cv::blur(image,result,cv::Size(3,3));
解释:这个类型的滤波器又称归一化块滤波器,选择3x3的核大小进行滤波。
,将像素用以像素为中心,权值如核内标的数字,想乘再相加代替。
在有些时候,我们想将离处理像素近的像素设置的权值大一点,这样滤波器效果更加接近源图像,因此这里提供了高斯滤波器cv::GaussianBlur。权重的选择来源于高斯曲线。通过函数参数确定高斯曲线的曲率。
函数定义:
CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT );函数实例:cv::GaussianBlur(image,result,cv::Size(5,5),1.5);
函数解释:,高斯函数计算式,函数参数double sigmaX就是σ 的值。x是参数Size ksize决定,从[-4,..,0...4]。
当σ = 1.5 时,可以利用函数cv::Mat gauss= cv::getGaussianKernel(9,sigma,CV_32F);得到权值如下:
[0.00761 0.036075 0.10959 0.21345 0.26666 0.21345 0.10959 0.03608 0.00761 ]
如果想得到图像2维的高斯滤波,可以两次使用GaussianBlur函数,分别对水平和垂直方向滤波,然后通过函数cv::sepFilter2D进行卷积,合成2维。或者直接使用cv::filter2D函数。
上面两种滤波器都是线性滤波器,本节将介绍另外一种有独特优势的非线性滤波器---中值滤波器。
中值滤波器,顾名思义,就是选择像素和附近一系列值的中间值,所以它对消除高斯白噪声有很好的效果,确实,当一个突发的黑色或者白色像素突然出现在图片中时,这种中值滤波器,滤波效果比较好。中值滤波还有个优势就是保留了图像的边缘。
函数定义:CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize );
函数实例:cv::medianBlur(image,result,5);
函数解释:int ksize,表示内核大小,我们使用正方形区域,所以必须是奇数。
低通滤波器可以应用到改变图像尺寸中。假设你想改变图像的尺寸到源图像的一半,你可能觉着删除图像所有的偶数或者奇数的列和行,然后就得到缩小的图像,但是这个想法不好,比如源图像的斜边缘会出现阶梯,曲线和纹理也会出现锯齿状的扭曲。当你想把高频的组件显示在小尺寸图像里面时会出现空间假暇,确实小图像(只有几个像素)不能很好的表现出高频的纹理。所以我们在对尺寸变换是,要先通过低频滤波,把高频量消除。
在进行图像尺寸变换时,你缩小尺寸后,想恢复原来的图像是不可能的,因为图像信息损耗了。
我们有两种按图像尺寸顺序存储图像的结构叫金字塔,有向下采样的高斯金字塔,最底层为源图像,越往上尺寸越小。还有拉普拉斯金字塔,从金字塔底层重建上层图像。
我们介绍3个图像尺寸变换的函数
//! smooths and downsamples the image CV_EXPORTS_W void pyrDown( InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT ); //! upsamples and smoothes the image CV_EXPORTS_W void pyrUp( InputArray src, OutputArray dst, const Size& dstsize=Size(), int borderType=BORDER_DEFAULT );
//! resizes the image CV_EXPORTS_W void resize( InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0, int interpolation=INTER_LINEAR );
函数实例:
cv::Mat reducedImage; // to contain reduced image cv::pyrDown(image,reducedImage,cv::Size(image.cols/2,image.rows/2)); // reduce image size by half cv::pyrUp(image,reducedImage,cv::Size(image.cols*2,image.rows*2)); cv::resize(image,resizedImage,cv::Size(image.cols/3,image.rows/3)); // 1/3 resizing函数解释:pyrDown/pyrUp 的变换倍数必须是2的幂次,resize可以任意改变。
程序:
#include <iostream> #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> int main() { // Read input image cv::Mat image= cv::imread("boldt.jpg",0); if (!image.data) return 0; // Display the image cv::namedWindow("Original Image"); cv::imshow("Original Image",image); // Blur the image cv::Mat result; cv::GaussianBlur(image,result,cv::Size(5,5),1.5); // Display the blurred image cv::namedWindow("Gaussian filtered Image"); cv::imshow("Gaussian filtered Image",result); cv::imwrite("Gaussian filtered Image.jpg",result); // Get the gaussian kernel (1.5) cv::Mat gauss= cv::getGaussianKernel(9,1.5,CV_32F); // Display kernel values cv::Mat_<float>::const_iterator it= gauss.begin<float>(); cv::Mat_<float>::const_iterator itend= gauss.end<float>(); std::cout << "["; for ( ; it!= itend; ++it) { std::cout << *it << " "; } std::cout << "]" << std::endl; // Blur the image with a mean filter cv::blur(image,result,cv::Size(5,5)); // Display the blurred image cv::namedWindow("Mean filtered Image"); cv::imshow("Mean filtered Image",result); cv::imwrite("Mean filtered Image.jpg",result); // Read input image with salt&pepper noise image= cv::imread("salted.bmp",0); if (!image.data) return 0; // Display the S&P image cv::namedWindow("S&P Image"); cv::imshow("S&P Image",image); // Blur the image with a mean filter cv::blur(image,result,cv::Size(5,5)); // Display the blurred image cv::namedWindow("Mean filtered S&P Image"); cv::imshow("Mean filtered S&P Image",result); cv::imwrite("Mean filtered S&P Image.jpg",result); // Applying a median filter cv::medianBlur(image,result,5); // Display the blurred image cv::namedWindow("Median filtered S&P Image"); cv::imshow("Median filtered S&P Image",result); cv::imwrite("Median filtered S&P Image.jpg",result); // Reduce by 4 the size of the image (the wrong way) image= cv::imread("road.jpg",0); cv::Mat reduced(image.rows/2,image.cols/2,CV_8U); for (int i=0; i<reduced.rows; i++) for (int j=0; j<reduced.cols; j++) reduced.at<uchar>(i,j)= image.at<uchar>(i*2,j*2); // Display the reduced image cv::namedWindow("Badly reduced Image"); cv::imshow("Badly reduced Image",reduced); cv::imwrite("Badly reduced Image.jpg",reduced); cv::Mat resizedImage; // to contain reduced image cv::pyrDown(image,resizedImage,cv::Size(image.cols/2,image.rows/2)); // reduce image size by half cv::namedWindow("Right reduced Image"); cv::imshow("Right reduced Image",resizedImage); cv::imwrite("Right reduced Image.jpg",resizedImage); cv::pyrUp(image,resizedImage,cv::Size(image.cols*2,image.rows*2)); cv::namedWindow("amplification"); cv::imshow("amplification",resizedImage); cv::imwrite("amplification.jpg",resizedImage); cv::resize(image,resizedImage,cv::Size(image.cols/3,image.rows/3)); // 1/3 resizing cv::namedWindow("1/3 resizing Image"); cv::imshow("1/3 resizing Image",resizedImage); cv::imwrite("1/3 resizing Image.jpg",resizedImage); cv::waitKey(); return 0; }
boldt.jpg
Gaussian filtered Image.jpg
getGaussianKernel
Mean filtered Image.jpg
salted.bmp
Median filtered S&P Image.jpg
road.jpg
Badly reduced Image.jpg(公路左边的白线有明显的锯齿效果)
Right reduced Image.jpg
参考资料:OpenCV.2.Computer.Vision.Application.Programming.Cookbook chapter 6
程序下载:滤波器在图像处理中的应用(一)