OpenCV_图像滤波

来源:互联网 发布:淘宝网滥用商标关键字 编辑:程序博客网 时间:2024/05/22 00:20

滤波是信号和图像处理中的一种基本操作。它的目的时选择性地提取图像中某些方面的内容,这些内容在特定应用环境下传达了重要信息。

通过观察图像灰度值变化的频率来描述图像的特征,称为频域

通过观察图像灰度分布来描述图像特征,称为空域

有几种著名的变换法可以用来清楚地显示图像地频率成分,例如傅里叶变换或余弦变换。图像是二维的,因此频率分为两种,即垂直频率水平频率

在频域分析框架下,滤波器是一种放大图像中某些频段,同时滤掉其他频段的算子。

*低通滤波器

一个简单的方法是把每个像素的值替换成它周围像素的平均值。这样一来,强度的快速变化被消除,代之以更加平滑的过渡。

cv::blur函数将每个像素的值替换成该像素邻域的平均值。

效果:


代码:

int main(){cv::Mat image = cv::imread("zifeng.jpg");cv::imshow("original image", image);cv::Mat result;cv::blur(image, result, cv::Size(4, 4));cv::imshow("mean filtered image", result);cvWaitKey();}

有时需要让邻域内较近的像素具有更高的重要度,因此可计算加权平均值,即较近的像素比较远的像素具有更大的权重,可采用高斯函数指定的加权策略。


代码:

cv::GaussianBlur(image, result, cv::Size(5, 5), 1.5);cv::imshow("Gaussian filtered image", result);
如果用邻域像素的加权累加值来替换像素值,这种滤波器是线性的。
简单应用:

1、缩减像素采样

测试图像缩小1/4后(缩小的方式是每4行像素中保留一行),再将每个像素放大4倍得到的结果:


代码:

int main(){cv::Mat image = cv::imread("zifeng.jpg");cv::cvtColor(image, image, CV_BGR2GRAY);cv::imshow("original image", image);cv::Mat reduced(image.rows / 4, image.cols / 4,image.type());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 * 4, j * 4);//缩小的图像放大四倍,采用最邻近插值法cv::Mat result;cv::resize(reduced, result, cv::Size(), 4.0, 4.0, cv::INTER_NEAREST);cv::imshow("badly reduced", result);cvWaitKey();}

可以发现,图像的质量明显下降了,看到了锯齿状的变形。这些令人讨厌的伪影是一种叫做空间假频的现象造成的,当试图在图像中包含高频成分但图像太小无法包含时,就会出现这种现象。因此,在缩小图像之前应去除它的高频成分

效果:


锯齿效果有所改善。这是像素放大4倍的效果,实际缩小效果为:

进行双线性插值后:

代码:

int main(){cv::Mat image = cv::imread("zifeng.jpg");cv::cvtColor(image, image, CV_BGR2GRAY);cv::imshow("original image", image);cv::GaussianBlur(image, image, cv::Size(5,5), 2.0);cv::Mat reduced(image.rows / 4, image.cols / 4,image.type());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 * 4, j * 4);cv::Mat result;cv::resize(reduced, result, cv::Size(), 4, 4, cv::INTER_LINEAR);cv::imshow("result", result);cvWaitKey();}

可以看到,效果不是非常好,接着试试OpenCV专用于图像缩小的函数cv::pyrDown,图片尺寸缩小一半


自带函数同样也是先使用5*5高斯滤波器

*中值滤波器

中值滤波器属于非线性滤波器的一种,典型应用是消除椒盐噪声。

首先,我们为一副图像增加椒盐噪声:


然后进行中值滤波:


代码:

int main(){cv::Mat image = cv::imread("zifeng.jpg");int i, j;for (int count = 0; count < 3000; count++){i = std::rand() % image.rows;j = std::rand() % image.cols;image.at<cv::Vec3b>(i, j)[0] = 255;image.at<cv::Vec3b>(i, j)[1] = 255;image.at<cv::Vec3b>(i, j)[2] = 255;}cv::imshow("salted image", image);cv::Mat result;cv::medianBlur(image, result,5);cv::imshow("result", result);cvWaitKey();}

*用定向滤波器检测边缘

这属于一种高通滤波器,这里使用的滤波器称为Sobel滤波器。因为其只对垂直或水平方向的图像频率起作用,所以被认为是一种定向滤波器

这种滤波器可用来实现浮雕化特效



还可将两个结果组合得到sobel模,阈值化处理后得到图像轮廓的二值化分布图(故此算子称为边缘检测器)


代码:

int main(){cv::Mat image = cv::imread("zifeng.jpg");cv::cvtColor(image, image, CV_BGR2GRAY);cv::Mat sobelX, sobelY;cv::Sobel(image, sobelX, CV_8U, 1, 0, 3, 0.4, 128);cv::imshow("sobelX image", sobelX);cv::Sobel(image, sobelY, CV_8U, 0, 1, 3, 0.4, 128);cv::imshow("sobelY image", sobelY);cv::Mat sobel;sobel = abs(sobelX) + abs(sobelY);double sobmin, sobmax;cv::minMaxLoc(sobel, &sobmin, &sobmax);cv::Mat sobelImage;sobel.convertTo(sobelImage, CV_8U, -255. / sobmax, 255);cv::imshow("sobel image", sobelImage);cv::threshold(sobelImage, sobelImage, 36, 255, CV_THRESH_BINARY_INV);cv::imshow("binary sobel image", sobelImage);cvWaitKey();}


*计算拉普拉斯算子

拉普拉斯算子也是一种基于图像导数运算的高通线性滤波器,它通过计算二阶导数来度量图像函数的曲率。

效果:

代码:

LaplacianZC类:

class LaplacianZC{private:cv::Mat laplace;int aperture;public:LaplacianZC() :aperture(3){}void setAperture(int a){aperture = a;}cv::Mat computeLaplacian(const cv::Mat& image){cv::Laplacian(image, laplace, CV_32F, aperture);return laplace;}cv::Mat getLaplacianImage(double scale = -1.0){if (scale < 0){double lapmin, lapmax;cv::minMaxLoc(laplace, &lapmin, &lapmax);scale = 127 / std::max(-lapmin, lapmax);}cv::Mat laplaceImage;laplace.convertTo(laplaceImage, CV_8U, scale, 128);return laplaceImage;}};
main函数:

int main(){cv::Mat image = cv::imread("zifeng.jpg");LaplacianZC cLaplacian;cLaplacian.setAperture(7);cv::Mat flap = cLaplacian.computeLaplacian(image);cv::Mat laplaceImage = cLaplacian.getLaplacianImage();cv::imshow("laplace image", laplaceImage);cvWaitKey();}