OpenCV filter2D函数详解

     OpenCV filter2D函数简介   

        OpenCV filter2D将图像与内核进行卷积,将任意线性滤波器应用于图像。支持就地操作。当孔径部分位于图像之外时,该函数根据指定的边界模式插值异常像素值。

        该函数实际上计算相关性,而不是卷积:

  filter2D函数的原型如下:

        void cv::filter2D(InputArray src,

                                        OutputArray dst,

                                        int  ddepth,

                                        InputArray  kernel,

                                        Point  anchor = Point(-1,-1),

                                        double  delta = 0,

                                        int       borderType = BORDER_DEFAULT

                                        )

参数:

        src 输入图像

       dst  输出图像,与 src 大小相同、通道数相同

       ddepth  目标图像的所需深度

        kernel 卷积核(或者更确切地说是相关核),单通道浮点矩阵;如果要将不同的内核应用于                        不同的通道,请使用 split 将图像分割为单独的颜色平面并单独处理它们。

        anchor 内核的锚点,指示内核中过滤点的相对位置;锚应该位于内核内;默认值(-1,-1)                      表示锚点位于内核中心。

        delta  在将过滤像素存储到 dst 之前添加到过滤像素的可选值。

        borderType 像素外推方法。可以选以下几种:BORDER_CONSTANT,BORDER_REPLICATE,BORDER_REFLECT,BORDER_REFLECT_101,BORDER_TRANSPARENT,BORDER_REFLECT101,BORDER_DEFAULT,BORDER_ISOLATED。

        OpenCV filter2D函数应用

        使用OpenCV filter2D函数,通过改变卷积核(kernel)可达成不同的滤波效果。下面就OpenCV filter2D函数的几种常用场景做说明,并以实例做演示。

        图像锐化

        图像锐化使用的卷积核如下:

        Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);

        下面以实例演示图像锐化操作及锐化效果,示例代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
	Mat src = imread("1.jpg");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	
	imshow("Input Image", src);

	Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	imshow("Output Image", dst);

	waitKey(0);
	return 0;
}

试运行,结果如下:

        可以看到经过Filter2D滤波后的图像变得更清晰。

均值滤波

        OpenCV filter2D函数实现均值滤波的卷积核如下:

Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, 1, 1, 1, 1, 1) / 9;

下面以实例演示filter2D实现图像均值滤波操作及滤波效果,示例代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
	//sharp test
	/*
	Mat src = imread("1.jpg");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	
	imshow("Input Image", src);


	Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	imshow("Output Image", dst);
	*/

	//Mean filter test
	Mat src = imread("3.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	imshow("Input Image", src);

	Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, 1, 1, 1, 1, 1) / 9;
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	for (size_t i = 0; i < 15; i++)
	{
		filter2D(dst, dst, src.depth(), kernel);
	}
	imshow("Output Image", dst);

	waitKey(0);
	return 0;
}

       试运行,结果如下:

 

可以看出,均值滤波可以去除图像椒盐噪声,达到磨皮效果。

 高斯滤波

OpenCV filter2D函数实现高斯滤波的卷积核可由高斯核转换得到,方法如下:

Mat kernelGaussian = getGaussianKernel(9, 1.5);
Mat  kernel = kernelGaussian * kernelGaussian.t();

下面以实例演示filter2D实现图像高斯滤波操作及滤波效果,示例代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
	//filter2d sharp test
	/*
	Mat src = imread("1.jpg");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	
	imshow("Input Image", src);


	Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	imshow("Output Image", dst);
	*/

	//filter2d Mean filter test
	/*
	Mat src = imread("3.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	imshow("Input Image", src);

	Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, 1, 1, 1, 1, 1) / 9;
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	for (size_t i = 0; i < 15; i++)
	{
		filter2D(dst, dst, src.depth(), kernel);
	}
	imshow("Output Image", dst);
	*/

	//filter2d Gaussian filter test
	Mat src = imread("3.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	imshow("Input Image", src);

	Mat kernelGaussian = getGaussianKernel(9, 1.5);
	Mat  kernel = kernelGaussian * kernelGaussian.t();
	Mat dst;
	filter2D(src, dst, src.depth(), kernel);
	for (size_t i = 0; i < 6; i++)
	{
		filter2D(dst, dst, src.depth(), kernel);
	}
	imshow("Output Image", dst);

	waitKey(0);
	return 0;
}

试运行,结果如下:

可以看出,同样filter2D均高斯滤波同样可以去除图像椒盐噪声,达成磨皮效果,且所需次数更少。

 边缘检测

 filter2D还可以使用sobel内核实现边缘检测,soble内核如下:

Mat sobelX = (Mat_<float>(3, 3) << -1, 0, 1,-2, 0, 2,-1, 0, 1);
Mat sobelY = (Mat_<float>(3, 3) << -1, -2, -1,0, 0, 0,1, 2, 1);

下面以实例演示filter2D 用sobel核实现图像边缘检测操作及滤波效果,示例代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
	//filter2d sharp test
	/*
	Mat src = imread("1.jpg");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	
	imshow("Input Image", src);


	Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	imshow("Output Image", dst);
	*/

	//filter2d Mean filter test
	/*
	Mat src = imread("3.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	imshow("Input Image", src);

	Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, 1, 1, 1, 1, 1) / 9;
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	for (size_t i = 0; i < 15; i++)
	{
		filter2D(dst, dst, src.depth(), kernel);
	}
	imshow("Output Image", dst);
	*/

	//filter2d Gaussian filter test
	/*
	Mat src = imread("3.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	imshow("Input Image", src);

	Mat kernelGaussian = getGaussianKernel(9, 1.5);
	Mat  kernel = kernelGaussian * kernelGaussian.t();
	Mat dst;
	filter2D(src, dst, src.depth(), kernel);
	for (size_t i = 0; i < 6; i++)
	{
		filter2D(dst, dst, src.depth(), kernel);
	}
	imshow("Output Image", dst);
	*/

	//filter2d detect edges test
	Mat src = imread("4.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	threshold(src, src, 127, 255, THRESH_BINARY);
	imshow("Input Image", src);

	Mat sobelX = (Mat_<float>(3, 3) << -1, 0, 1,-2, 0, 2,-1, 0, 1);
	Mat sobelY = (Mat_<float>(3, 3) << -1, -2, -1,0, 0, 0,1, 2, 1);

	Mat edges,edgesX, edgesY;
	filter2D(src, edgesX, CV_16S, sobelX);
	filter2D(src, edgesY, CV_16S, sobelX);

	convertScaleAbs(edgesX, edgesX);
	convertScaleAbs(edgesY, edgesY);
	addWeighted(edgesX, 0.5, edgesY, 0.5, 0, edges);

	imshow("Edges", edges);

	waitKey(0);
	return 0;
}

试运行,结果如下:

        可以看出确实检测到了边缘,效果并不是很好。

        filter2D还可以使用Prewitt核,实现边缘检测。Prewitt核如下:

        Mat prewitt_x = (Mat_<int>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);
        Mat prewitt_y = (Mat_<int>(3, 3) << -1, -1, -1,0, 0, 0, 1, 1, 1);

        下面以实例演示filter2D 用Prewitt核实现图像边缘检测操作及滤波效果,示例代码如下:

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
	//filter2d sharp test
	/*
	Mat src = imread("1.jpg");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	
	imshow("Input Image", src);


	Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	imshow("Output Image", dst);
	*/

	//filter2d Mean filter test
	/*
	Mat src = imread("3.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	imshow("Input Image", src);

	Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, 1, 1, 1, 1, 1) / 9;
	Mat dst;

	filter2D(src, dst, src.depth(), kernel);
	for (size_t i = 0; i < 15; i++)
	{
		filter2D(dst, dst, src.depth(), kernel);
	}
	imshow("Output Image", dst);
	*/

	//filter2d Gaussian filter test
	/*
	Mat src = imread("3.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	imshow("Input Image", src);

	Mat kernelGaussian = getGaussianKernel(9, 1.5);
	Mat  kernel = kernelGaussian * kernelGaussian.t();
	Mat dst;
	filter2D(src, dst, src.depth(), kernel);
	for (size_t i = 0; i < 6; i++)
	{
		filter2D(dst, dst, src.depth(), kernel);
	}
	imshow("Output Image", dst);
	*/

	//filter2d detect edges test
	/*
	//sobel kernel
	Mat src = imread("4.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	threshold(src, src, 127, 255, THRESH_BINARY);
	imshow("Input Image", src);

	Mat sobelX = (Mat_<float>(3, 3) << -1, 0, 1,-2, 0, 2,-1, 0, 1);
	Mat sobelY = (Mat_<float>(3, 3) << -1, -2, -1,0, 0, 0,1, 2, 1);

	Mat edges,edgesX, edgesY;
	filter2D(src, edgesX, CV_16S, sobelX);
	filter2D(src, edgesY, CV_16S, sobelX);

	convertScaleAbs(edgesX, edgesX);
	convertScaleAbs(edgesY, edgesY);
	addWeighted(edgesX, 0.5, edgesY, 0.5, 0, edges);

	imshow("Edges", edges);
	*/

	//Prewitt kernel
	Mat src = imread("4.png");
	if (src.empty())
	{
		cout << "Cann't open Image" << endl;
		return -1;
	}
	threshold(src, src, 127, 255, THRESH_BINARY);
	imshow("Input Image", src);

	Mat prewitt_x = (Mat_<int>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);
	Mat prewitt_y = (Mat_<int>(3, 3) << -1, -1, -1,0, 0, 0, 1, 1, 1);
	
	Mat edges, edgesX, edgesY;
	filter2D(src, edgesX, src.depth(), prewitt_x);
	filter2D(src, edgesY, src.depth(), prewitt_y);
	addWeighted(edgesX, 0.5, edgesY, 0.5, 0, edges);

	imshow("Edges", edges);

	waitKey(0);
	return 0;
}

试运行,结果如下:

        从结果可以看出,filter2D使用Prewitt核检测边缘的结果,与使用sobel核边缘检测的结果是有差异的。

      OpenCV  filter2D函数就介绍到这里。博文示例是基于OpenCV4.8(opencv目录位于d盘根目录下)及VS2022。示例源码已上传到CSDN,其链接为:https://mp.csdn.net/mp_blog/creation/editor/136590730

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bill66

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值