1.生成卷积核
生成卷积核,一般用于生成一些常见的核,比如Sobel核和Scharr核以及Gaussian核。
首先来看导数滤波器的核,Sobel核和Scharr的核,这两个核都属于可分解核,可以分解为一个列向量ky和一个行向量kx。先来看一看导数滤波器函数:
getDerivKernels(
OutputArray kx, //X方向的核
OutputArray ky, //Y方向的核
int dx, //如果需要输出X方向的核则设置为1 否则为0
int dy, //如果需要输出Y方向的核则设置为1 否则为0
int ksize, //核的大小
bool normalize=true,//元素是否规范化
int ktype = CV_32F //滤波器类型(默认和kx,ky类型相同)
);
对于参数ksize我们可以取1,3,5,7,这是得到sobel核,也可以取SCHARR得到的就是scharr核。
对于元素是否归范化,如果是浮点型的图像应该规范化。如果图像为整形那么就设置为false,否则会导致精度丢失。
我们使用的高斯滤波函数是由opencv提供的,当然我们也可以先得到高斯核在进行高斯滤波
Mat getGaussianKernel(
int ksize, //卷积核大小
double sigma, //正态分布方差
int ktype=CV_32F, //滤波器的类型
);
具体的参数我们已经在高斯滤波器那一节详细讲解过了,这边我们就不再学习,但是值得注意点是我们可以设置sigma=-1,ksize将自动计算,且ksize必须为奇数。
我们得到了卷积核那么我们需要用卷积核进行卷积运算
2.卷积运算
我们通常直接使用相应功能的滤波函数直接完成卷积运算,但是我们若是自定义了一个核,我们就需要使用卷积函数进行卷积运算,当然我们可以遍历整个数组然后再进行卷积运算,但是操作过于复杂我们直接用OpenCV完成并进行优化。OpenCV提供了两个函数来实现这个功能,一个是filter2D(),另一个是sepFilter2D()
先来看filter2D()
void filter2D(
InputArray src, //输入图像
OutputArray dst, //输出图像
int ddepth, //输出图像数据类型
InputArray kernel, //输入卷积核
Point anchor=Point(-1,-1),//中心像素对齐方式
double delta=0, //结果灰度是否需要加减delta
int borderType=BORDER_DEFAULT//默认边缘平滑方式
);
这个函数中需要注意点是ddepth这个参数,满足下表,否则可能发生截断
还有一个函数sepFilter2D()相较于filter2D(),这个函数用于参与卷积运算的核是可分核,也就是X方向和Y方向的核
void sepFilter2D(
InputArray src, //输入图像
OutputArray dst, //输出图像
int ddepth, //输出图像深度
InputArray rowKernel, //输入X方向的核
InputArray columnKernel, //输入Y方向的核
Point anchor=Point(-1,-1), //中心像素对齐方式
double delta, //中心像素灰度加减delta
int borderType=BORDER_DEFAULT//边缘平滑方式
);
3.自定义核
自定义核指的是我们对卷积核的大小和形状进行设置
Mat getStructuringElement(
int shape, //卷积核形状
Size ksize, //卷积核大小
Point anchor=Point(-1,-1)//默认锚点在卷积核中心
);
卷积核形状参数列表
enum{
MORPH_RECT,
MORPH_ELLIPSE,
MORPH_CROSS
}
4.可拆分卷积核
先来说明一下什么是可拆分核
一个卷积核可以看做一个1*n的核和一个n*1的核做卷积运算,便称为可拆分卷积核
I是一个图像的核,和一个卷积核做卷积运算,可以认为这个图像的核分别与这个1*n的核和n*1的核做卷积运算,那么这么做有什么好处呢,可以减少时间复杂度。(这个的推导过程我就不详细写了感兴趣的可以自行推导)这也是为什么我们要将一个卷积核拆分成两个核的卷积,同时随着图像的变大,运算的优越性越明显。