图像卷积是我们对图像进行处理时最常用的方法,如去噪、滤波、边缘提取等都要用的卷积函数。OpenCV中提供了不同方法的卷积函数,包括Sobel算子、Laplace算子、Canny边缘检测算子等等,除了这些自带的函数,OpenCV库中还提供一种可以自定义卷积核的函数,可由用户自己根据需要定义合适的卷积核。
先学习下OpenCV中自带的卷积函数
Sobel算子
OpenCV中Sobel算子被封装在
CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth,
int dx, int dy, int ksize=3,
double scale=1, double delta=0,
int borderType=BORDER_DEFAULT );
这个函数里面,其中:src表示输入原图像;dst表示输出目标图像;ddepth表示用来度量每一个像素中每一个通道的精度,但它本身与图像的通道数无关!depth数值越大,精度越高。在Opencv中,Mat.depth()得到的是一个0~6的数字,分别代表不同的位数,对应关系如下:
enum{CV_8U=0,CV_8S=1,CV_16U=2,CV_16S=3,CV_32S=4,CV_32F=5,CV_64F=6},ddepth 由于Sobel运算时可能会出现比较大的值,因此取值方式有以下几种:
- 若 ddepth = CV_8U, 取 ddepth = -1 或 CV_16S 或 CV_32F 或 CV_64F
- 若 ddepth = CV_16U, 或 CV_16S, 取 ddepth = -1 或 CV_32F 或 CV_64F
- 若 ddepth = CV_32F, 取 ddepth = -1 或 CV_32F 或 CV_64F
- 若 ddepth = CV_64F, 取 ddepth = -1 或 CV_64F
- 若 ddepth = -1, 代表输出图像与输入图像相同的深度。
dx表示对X方向进行求导的差分阶数;dy表示对Y方向进行求导的差分阶数;
其中, dx=1,dy=0,表示计算X方向的导数,检测出的是垂直方向上的边缘;dx=0,dy=1,表示计算Y方向的导数,检测出的是水平方向上的边缘。
ksize 表示卷积核的大小,只能为奇数 1、3、5、7 等,特殊情况:当ksize <= 0 时,采用的模板为3 * 3 的Scharr内核。
当ksize=3时,Sobel内核可能产生比较明显的误差,此时,可以使用 Scharr 函数,该函数仅作用于大小为3的内核。具有跟sobel一样的速度,但结果更精确,其内核为:
( Gx ) [ − 3 0 + 3 − 10 0 + 10 − 3 0 + 3 ] \left[ \begin{matrix} -3 & 0 & +3 \\ -10 & 0 & +10 \\ -3 & 0 & +3 \end{matrix} \right] \tag{ Gx } ⎣⎡−3−10−3000+3+10+3⎦⎤( Gx )
( Gy ) [ − 3 − 10 − 3 0 0 0 + 3 + 10 + 3 ] \left[ \begin{matrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ +3 & +10 & +3 \end{matrix} \right] \tag{ Gy } ⎣⎡−30+3−100+10−30+3⎦⎤( Gy )
其调用格式为:
/// 求 X方向梯度
Sobel(src_gray,grad_x,ddepth, 1, 0, CV_SCHARR, scale, delta, BORDER_DEFAULT );
/// 求 Y方向梯度
Sobel(src_gray,grad_y,ddepth, 0, 1, CV_SCHARR, scale, delta, BORDER_DEFAULT );
double scale:默认1。
double delta:默认0。
int borderType:默认值为BORDER_DEFAULT。
调用 Sobel 实现图像效果如下:
对 X 方向求导
对 Y 方向求导
Laplace算子
Laplace算子也是一种边缘检测算子,与Sobel算子不同的地方为它是二阶微分求导,Sobel为一阶