OpenCV_图像滤波

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

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

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

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

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

*低通滤波器

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

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

效果:

OpenCV_图像滤波_第1张图片

代码:

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();
}

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

OpenCV_图像滤波_第2张图片

代码:

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

1、缩减像素采样

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

OpenCV_图像滤波_第3张图片

代码:

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(i, j) = image.at(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();
}

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

效果:

OpenCV_图像滤波_第4张图片

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

OpenCV_图像滤波_第5张图片
进行双线性插值后:
OpenCV_图像滤波_第6张图片
代码:

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(i, j) = image.at(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,图片尺寸缩小一半

OpenCV_图像滤波_第7张图片

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

*中值滤波器

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

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

OpenCV_图像滤波_第8张图片

然后进行中值滤波:

OpenCV_图像滤波_第9张图片

代码:

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(i, j)[0] = 255;
		image.at(i, j)[1] = 255;
		image.at(i, j)[2] = 255;
	}
	cv::imshow("salted image", image);
	cv::Mat result;
	cv::medianBlur(image, result,5);
	cv::imshow("result", result);
	cvWaitKey();
}

*用定向滤波器检测边缘

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

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

OpenCV_图像滤波_第10张图片

OpenCV_图像滤波_第11张图片

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

OpenCV_图像滤波_第12张图片

代码:

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();
}


*计算拉普拉斯算子

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

效果:

OpenCV_图像滤波_第13张图片

代码:

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();
}




你可能感兴趣的:(OpenCV)