OpenCV实战(13)——高通滤波器及其应用

Posted 盼小辉丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV实战(13)——高通滤波器及其应用相关的知识,希望对你有一定的参考价值。

OpenCV实战(13)——高通滤波器以及应用

0. 前言

在频域分析中,滤波器是一种放大图像某些频带同时减少其他频带的操作,低通滤波器 (low-pass filters) 是消除图像高频成分的滤波器,而高通滤波器 (high-pass filters) 消除图像的低频成分。在《滤波器》一节中,已经介绍了低通滤波器的实现以及应用,在本节中,我们介绍另一类重要的滤波器,即高通滤波器。

1. 检测图像边缘

《滤波器》一节中,我们已经介绍了如何使用核矩阵进行线性滤波,使用低通滤波器通过去除或衰减图像高频分量来模糊图像。在本节中,我们将执行相反的变换,即放大图像的高频内容,介绍高通滤波器用于执行边缘检测。

1.2 Sobel 滤波器

本节主要介绍 Sobel 滤波器,它也被称为定向滤波器,因为它仅影响垂直或水平图像频率,具体取决于使用的滤波器核。

(1) 要在水平方向应用 Sobel 算子,使用以下参数调用函数:

cv::Mat sobelX;
cv::Sobel(image,        // 输入
        sobelX,         // 输出
        CV_8U,          // 图像类型
        1, 0,           // 核
        3,              // 核大小
        0.4, 128);      // 缩放和偏移因子

(2) 垂直滤波与水平滤波类似,可以通过使用以下方式实现:

cv::Sobel(image, sobelY, CV_8U, 0, 1, 3, 0.4, 128);

生成的输出用 8 位图像 (CV_8U) 表示。水平 Sobel 算子操作结果如下所示:

Sobel 算子的核包含正值和负值,Sobel 滤波器的结果通常用 16 位有符号整数图像 (CV_16S) 计算,为了使结果可显示为 8 位图像,我们使用如下表示:使用零值对应于灰度级 128,负值由较暗的像素表示,而正值由较亮的像素表示。垂直 Sobel 算子操作结果如下所示:

以上图像类似于照片编辑软件中的浮雕效果,实际上,浮雕图像转换通常基于方向滤镜完成。

(3) 然后将以上两个结果(垂直和水平 Sobel )进行组合,以获得 Sobel 滤波器的范数结果:

// 计算 Sobel 范数
cv::Sobel(image, sobelX, CV_16S, 1, 0);
cv::Sobel(image, sobelY, CV_16S, 0, 1);
cv::Mat sobel;
sobel = abs(sobelX) + abs(sobelY);

(4) 使用 convertTo 方法的缩放参数可以在图像中显示 Sobel 范数结果,得到的图像中使用零值表示白色像素,而较大的值用于表示灰色阴影:

double sobmin, sobmax;
cv::minMaxLoc(sobel, &sobmin, &sobmax);
// 转换为 8 位图像
cv::Mat sobelImage;
sobel.convertTo(sobelImage, CV_8U, -255./sobmax, 255)

从上图中可以看出 Sobel 算子被称为边缘检测器的原因,对该图像进行阈值处理,可以获得图像轮廓的二值图:

// 对 Sobel 范数应用阈值
cv::Mat sobelThresholded;
cv::threshold(sobelImage, sobelThresholded, 225, 255, cv::THRESH_BINARY);

Sobel 算子是一个经典的边缘检测线性滤波器,它基于简单的 3x3 核,垂直和水平核分别具有以下结构:

[ − 1 0 1 − 2 0 2 − 1 0 1 ] [ − 1 − 2 − 1 0 0 0 1 2 1 ] \\left[ \\beginarrayccc -1 & 0 & 1\\\\ -2 & 0 & 2\\\\ -1 & 0 & 1\\\\\\endarray\\right] \\left[ \\beginarrayccc -1 & -2 & -1\\\\ 0 & 0 & 0\\\\ 1 & 2 & 1\\\\\\endarray\\right] 121000121 101202101

如果我们将图像视为一个二维函数,那么 Sobel 算子就可以看作是图像在垂直和水平方向上的变化的度量。在数学中,这种度量称为梯度,定义为由函数在两个正交方向上的一阶导数构成的二维向量:
g r a d ( I ) = [ ∂ I ∂ x , ∂ I ∂ y ] T grad(I)=[\\frac \\partial I \\partial x,\\frac \\partial I \\partial y]^T grad(I)=[xI,yI]T
因此,Sobel 算子在水平和垂直方向上计算图像梯度的近似值,对目标像素周围的窗口进行操作,以减少噪声的影响。cv::Sobel 函数计算图像与 Sobel 核的卷积结果,其完整调用形式如下:

cv::Sobel(image,            // 输入
        sobel,              // 输出
        image_depth,        // 图像类型
        xorder, yorder,     // 指定核
        kernel_size,        // 核尺寸
        alpha, beta);       // 缩放和偏移

我们可以将结果写入无符号字符、有符号整数或浮点图像,如果结果落在图像像素域之外,将应用饱和运算。最后两个参数用于将结果存储在图像中之前将结果缩放(乘以) alpha 并添加偏移量 beta,在上一节生成的图像中,Sobel0 由中灰度级 128 表示;每个 Sobel 掩码对应一个方向的导数,因此,使用两个参数来指定应用的内核:xy 方向的导数阶数,例如,通过为 xorderyorder 参数指定 10 来使用水平 Sobel 核,将而指定 01 则使用垂直 Sobel 核,我们也可以使用其他组合,但这两种是最常用的组合(二阶导数将在下一节中介绍);最后,也可以使用其他尺寸的核,例如,值 1357,大小为 1 的核对应于一维 Sobel 滤波器( 1x33x1)。
由于梯度是一个二维向量,它包含一个范数和一个方向,梯度向量的范数表示梯度变化的幅度,它通常使用欧几里得范数(也称为 L2 范数)计算:
∣ g r a d ( I ) ∣ = ( ∂ I ∂ x ) 2 + ( ∂ I ∂ y ) 2 |grad(I)|=\\sqrt (\\frac \\partial I \\partial x)^2+(\\frac \\partial I \\partial y)^2 grad(I)=(xI)2+(yI)2
然而,在图像处理中,梯度范数通常使用 L1 范数计算(绝对值之和),它可以以更低的计算成本得到接近 L2 范数的计算结果:

sobel= abs(sobelX)+abs(sobelY);

梯度向量总是指向变化最陡峭的方向,对于图像而言,这意味着梯度方向会与边缘正交,从较暗的方向指向较亮的方向,梯度方向可以使用以下公式计算:
a t a n ( g r a d ( I ) ) atan(grad(I)) atan(grad(I))
大多数情况下,对于边缘检测,只需要计算范数。但是,如果同时需要范数和方向,可以使用以下 OpenCV 函数:

cv::Sobel(image, sobelX, CV_32F, 1, 0);
cv::Sobel(image, sobelY, CV_32F, 0, 1);
// 计算梯度的 L2 范数和方向
cv::Mat norm, dir;
cv::cartToPolar(sobelX, sobelY, norm, dir);

默认情况下,方向以弧度计算,需添加 true 作为附加参数将弧度制转换为角度值。
通过在梯度幅度上应用阈值,可以获得二值边缘图像,其关键在于设置合适的阈值。如果阈值太低,会保留太多(粗)边缘,而如果阈值太高,则会得到较多断边。例如下图是使用较高阈值得到的二值边缘图像:

可以使用滞后阈值技术获得合适的阈值。也可以在应用微分滤波器之前应用高斯平滑滤波器,能够降低噪声影响。接下来,我们将介绍一些其他梯度算子。

1.2 梯度算子

为了估计像素位置的梯度,Prewitt 算子使用以下矩阵核:
[ − 1 0 1 − 1 0 1 − 1 0 1 ] [ − 1 − 1 − 1 0 0 0 1 1 1 ] \\left[ \\beginarrayccc -1 & 0 & 1\\\\ -1 & 0 & 1\\\\ -1 & 0 & 1\\\\\\endarray\\right] \\left[ \\beginarrayccc -1 & -1 & -1\\\\ 0 & 0 & 0\\\\ 1 & 1 & 1\\\\\\endarray\\right] 111000111 101101101
Roberts 算子基于简单的 2x2 矩阵核:
[ 1 0 0 − 1 ] [ 0 1 − 1 0 ] \\left[ \\beginarrayccc 1 & 0\\\\ 0 & -1\\\\\\endarray\\right] \\left[ \\beginarrayccc 0 & 1\\\\ -1 & 0\\\\\\endarray\\right] [1001][0110]
当需要更准确地估计梯度方向时,应当首选 Scharr 算子:
[ − 3 0 3 − 10 0 10 − 3 0 3 ] [ − 3 − 10 − 3 0 0 0 1 1 1 ] \\left[ \\beginarrayccc -3 & 0 & 3\\\\ -10 & 0 & 10\\\\ -3 & 0 & 3\\\\\\endarray\\right] \\left[ \\beginarrayccc -3 & -10 & -3\\\\ 0 & 0 & 0\\\\ 1 & 1 & 1\\\\\\endarray\\right] 31030003103 301以上是关于OpenCV实战(13)——高通滤波器及其应用的主要内容,如果未能解决你的问题,请参考以下文章

第三章:用opencv3处理图像

OpenCV 完整例程86. 频率域滤波应用:指纹图像处理

OpenCV-高斯低通&高通滤波器(C++)

OpenCV 完整例程84. 由低通滤波器得到高通滤波器

【转载】opencv 频域高通、低通滤波演示

OpenCV 完整例程66. 图像滤波之低通/高通/带阻/带通