OpenCV 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);
下面以实例演示图像锐化操作及锐化效果,示例代码如下:
void QuickDemo::nineth(Mat image) {
Mat sharpenImage;
Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(image, sharpenImage, image.depth(), kernel, Point(-1, -1), 0);
namedWindow("锐化", WINDOW_AUTOSIZE);
imshow("锐化", sharpenImage);
}
可以看到经过Filter2D滤波后的图像变得更清晰。
均值滤波
OpenCV filter2D函数实现均值滤波的卷积核如下:
Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, 1, 1, 1, 1, 1) / 9;
下面以实例演示filter2D实现图像均值滤波操作及滤波效果,示例代码如下:
void QuickDemo::nineth(Mat image) {
Mat blurImage;
Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, 1, 1, 1, 1, 1)/9;
filter2D(image, blurImage, image.depth(), kernel, Point(-1, -1));
namedWindow("均值滤波", WINDOW_AUTOSIZE);
imshow("均值滤波", blurImage);
}
可以看出,均值滤波可以去除图像椒盐噪声,达到磨皮效果。
高斯滤波
OpenCV filter2D函数实现高斯滤波的卷积核可由高斯核转换得到,方法如下:
Mat kernelGaussian = getGaussianKernel(9, 1.5);
Mat kernel = kernelGaussian * kernelGaussian.t();
getGaussianKernel( int ksize, double sigma, int ktype = CV_32F );
参数说明:
ksize
:高斯核的大小。它必须是大于零的奇数。
sigma
:高斯核的标准差。如果它等于零,那么根据ksize自动选择。
ktype
:矩阵的类型。默认值为CV_32F
。返回值:
一个
ksize
x 1的列矩阵,表示高斯核。
下面以实例演示filter2D实现图像高斯滤波操作及滤波效果,示例代码如下:
void QuickDemo::nineth(Mat image) {
Mat gauBlurImage;
//Mat kernel = (Mat_<float>(3, 3) << 1, 1, 1, 1, 1, 1, 1, 1, 1)/9;
Mat kernelGaussian = getGaussianKernel(9, 1.5);
Mat kernel = kernelGaussian * kernelGaussian.t();
filter2D(image, gauBlurImage, image.depth(), kernel, Point(-1, -1));
namedWindow("高斯滤波", WINDOW_AUTOSIZE);
imshow("高斯滤波", gauBlurImage);
}
可以看出,同样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核实现图像边缘检测操作及滤波效果,示例代码如下:
void QuickDemo::nineth(Mat image) {
threshold(image, image, 200, 255, THRESH_BINARY);
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(image, edgesX, CV_16S, sobelX);
filter2D(image, edgesY, CV_16S, sobelY);
convertScaleAbs(edgesX, edgesX);
convertScaleAbs(edgesY, edgesY);
addWeighted(edgesX,0.5,edgesY,0.5,0,edges);
namedWindow("边缘检测", WINDOW_AUTOSIZE);
imshow("边缘检测", edges);
}
可以看出确实检测到了边缘,效果并不是很好。
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核实现图像边缘检测操作及滤波效果,示例代码如下:
void QuickDemo::nineth(Mat image) {
threshold(image, image, 127, 255, THRESH_BINARY);
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(image, edgesX, CV_16S, prewitt_x );
filter2D(image, edgesY, CV_16S, prewitt_y );
convertScaleAbs(edgesX, edgesX);
convertScaleAbs(edgesY, edgesY);
addWeighted(edgesX,0.5,edgesY,0.5,0,edges);
namedWindow("边缘检测", WINDOW_AUTOSIZE);
imshow("边缘检测", edges);
}
从结果可以看出,filter2D使用Prewitt核检测边缘的结果,与使用sobel核边缘检测的结果是有差异的。