边缘检测滤波器
Scharr算子只有两种滤波器,Sobel算子却有不同尺寸、不同阶次
在实际使用过程中,即使了解Sobel算子的原理,推导出边缘提取需要的滤波器也是非常复杂而繁琐的任务
并且,有时我们并不希望提取图像的边缘,而是希望得到能够提取图像边缘的滤波器,通过对滤波器的修改提升边缘检测的效果
OpenCV4提供了getDerivKernel()函数,通过函数可以得到不同尺寸、不同阶次的Sobel算子和Scharr算子的滤波器
getDerivKernel()函数原型:
void getDerivKernel(OutputArray kx,
OutputArray ky,
int dx,
int dy,
bool normlize = flase,
int ktype = CV_32F
)
- kx:行滤波器系数的输出矩阵,尺寸为 ksize x 1
- ky:列滤波器系数的输出矩阵,尺寸为 ksize x 1
- dx:X方向导数的阶次
- dy:Y方向导数的阶次
- ksize:滤波器的大小,可以选择参数为FILTER_SCHARR、1、3、5或7
- normalize:是否对滤波器系数进行归一化的标志,默认值为false,表示不进行系数归一化
- ktype:滤波器系数类型,可以选择CV_32F或CV_64F,默认为CV_32F
该函数可用于生成Sobel算子和Scharr算子,实际上,Sobel()函数和Scharr()函数内部就是通过调用该函数得到边缘检测算子
该函数的前两个参数分别为行滤波器系数的输出矩阵、列滤波器系数的输出矩阵,需要将两者通过卷积分离性原理得到最终的算子
最终的边缘检测算子对图像的边缘提取效果由第三、四个参数决定
当dx=1,dy=0时,就是检测X方向的一阶梯度边缘
该函数的第五个参数是滤波器的尺寸,取值为1、3、5、7,生成的是Sobel算子,取值为FILTER_SCHARR,生成的是Scharr算子
当第五个参数为1时,第三、四个参数最大值小于3
当第五个参数为FILTER_SCHARR时,第三、四个参数取值为1或0,并且两者和为1
示例:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat sobel_x1,sobel_y1,sobel_x2,sobel_y2,sobel_x3,sobel_y3; //存放分离的Sobel算子
Mat scharr_x,scharr_y; //存放分离的Scharr算子
Mat sobelX1,sobelX2,sobelX3,scharrX;//存放最终算子
//一阶X方向Sobel算子
getDerivKernels(sobel_x1,sobel_y1,1,0,3);
sobel_x1 = sobel_x1.reshape(CV_8U,1);
sobelX1 = sobel_y1*sobel_x1; //计算滤波器
//二阶X方向Sobel算子
getDerivKernels(sobel_x2,sobel_y2,2,0,5);
sobel_x2 = sobel_x2.reshape(CV_8U,1);
sobelX2 = sobel_y2*sobel_x2; //计算滤波器
//三阶X方向Sobel算子
getDerivKernels(sobel_x3,sobel_y3,3,0,7);
sobel_x3 = sobel_x3.reshape(CV_8U,1);
sobelX3 = sobel_y3*sobel_x3; //计算滤波器
//X方向Scharr算子
getDerivKernels(scharr_x,scharr_y,1,0,FILTER_SCHARR);
scharr_x = scharr_x.reshape(CV_8U,1);
scharrX = scharr_y*scharr_x; //计算滤波器
//输出结果
cout << "X方向一阶Sobel算子:" << endl << sobelX1 << endl;
cout << "X方向二阶Sobel算子:" << endl << sobelX2 << endl;
cout << "X方向三阶Sobel算子:" << endl << sobelX3 << endl;
cout << "X方向Scharr算子:" << endl << scharrX << endl;
waitKey(0);
return 0;
}
注:提取X方向和Y方向边缘的滤波器系数是互为转置的关系