大尺寸的Sobel滤波器内核
computer-vision
edge-detection
image-processing
5
0

我正在使用大小为3x3的sobel滤波器来计算图像导数。在互联网上的一些文章中,似乎5x5和7x7大小的sobel过滤器的内核也很常见,但是我找不到它们的内核值。

有人可以让我知道5x5和7x7大小的sobel滤波器的内核值吗?同样,如果有人可以共享一种方法来生成内核值,那将非常有用。

提前致谢。

参考资料:
Stack Overflow
收藏
评论
共 6 个回答
高赞 时间 活跃

根据@Paul R给出的示例,我迅速修改了一种算法,以生成任何奇数大小> 1的Sobel内核:

    public static void CreateSobelKernel(int n, ref float[][] Kx, ref float[][] Ky)
    {
        int side = n * 2 + 3;
        int halfSide = side / 2;
        for (int i = 0; i < side; i++)
        {
            int k = (i <= halfSide) ? (halfSide + i) : (side + halfSide - i - 1);
            for (int j = 0; j < side; j++)
            {
                if (j < halfSide)
                    Kx[i][j] = Ky[j][i] = j - k;
                else if (j > halfSide)
                    Kx[i][j] = Ky[j][i] = k - (side - j - 1);
                else
                    Kx[i][j] = Ky[j][i] = 0;
            }
        }
    }

希望能帮助到你。

收藏
评论

针对任意Sobel核尺寸和角度的完整解决方案

tl; dr:跳至“示例”部分

要添加另一种解决方案,请在本文档中进行扩展(质量不是特别高,但是从第2页的底部开始显示了一些可用的图形和矩阵)。

目标

我们试图做的是估计图像在位置(x,y)的局部梯度。梯度是一个矢量,由x和y方向的分量gx和gy组成。

现在,假设我们要基于像素(x,y)及其相邻像素,将其近似为内核操作(3x3、5x5或任何大小)。

解决思路

我们可以通过对所有相邻中心对在梯度方向上的投影求和来近似梯度。 (Sobel的内核只是加权不同贡献的一种特殊方法,基本上Prewitt也是这样)。

3x3的显式中间步骤

这是局部图像,中心像素(x,y)标记为“ o”(中心)

a b c
d o f
g h i

假设我们要在正x方向上渐变。正x方向的单位矢量为(1,0)[我稍后将使用以下约定:正y方向为DOWN,即(0,1),并且(0,0)在图像的左上方) 。]

从o到f的向量(简称“ of”)为(1,0)。方向“ of”上的梯度为(f-o)/ 1(此处像素处的图像值表示为f减去中心o处的值除以这些像素之间的距离)。如果我们通过点积将该特定邻域梯度的单位矢量投影到我们所需的梯度方向(1,0)上,则得到1。这是一张包含所有邻域贡献的小表,从较简单的情况开始。请注意,对于对角线,其距离为sqrt2,对角线方向的单位向量为1 / sqrt2 *(+/- 1,+/- 1)

f:   (f-o)/1     * 1
d:   (d-o)/1     * -1       because (-1, 0) dot (1, 0) = -1
b:   (b-o)/1     * 0        because (0, -1) dot (1, 0) = 0
h:   (h-o)/1     * 0        (as per b)
a:   (a-o)/sqrt2 * -1/sqrt2 distance is sqrt2, and 1/sqrt2*(-1,-1) dot (1,0) = -1/sqrt2
c:   (c-o)/sqrt2 * +1/sqrt2   ...
g:   (g-o)/sqrt2 * -1/sqrt2   ...
i:   (i-o)/sqrt2 * +1/sqrt2   ...

编辑以澄清问题:出于以下原因,存在两个因素1 / sqrt(2):

  1. 我们对特定方向 (此处为x)上的梯度贡献感兴趣,因此我们需要将从中心像素到相邻像素的方向梯度投影到我们感兴趣的方向上。这可以通过获取标量积来实现。单位向量在各个方向上的位置,这引入了第一个因子1 / L(此处对角线为1 / sqrt(2))。

  2. 梯度测量了一个点的无穷小变化,我们可以通过有限差分来近似。根据线性方程,m =(y2-y1)/(x2-x1)。因此,从中心像素到相邻像素(y2-y1)的值差必须分布在它们的距离(对应于x2-x1)上,以便获得每个距离单位的上升单位。这产生第二个因子1 / L(这里对角线为1 / sqrt(2))

好的,现在我们知道了贡献。让我们通过组合成对的相对像素贡献来简化此表达式。我将从d和f开始:

{(f-o)/1 * 1} + {(d-o)/1 * -1}
= f - o - (d - o)
= f - d

现在第一个对角线:

{(c-o)/sqrt2 * 1/sqrt2} + {(g-o)/sqrt2 * -1/sqrt2}
= (c - o)/2 - (g - o)/2
= (c - g)/2

第二个对角线贡献(i-a)/ 2。垂直方向为零。注意,来自中心像素“ o”的所有贡献都消失了。

现在,我们已经计算了像素(x,y)上所有正邻在x方向上对梯度的所有贡献,因此我们在x方向上对梯度的总近似值就是它们的和:

gx(x,y) = f - d + (c - g)/2 + (i - a)/2

我们可以使用卷积内核获得相同的结果,其中将系数写在相应的相邻像素的位置:

-1/2  0  1/2
 -1   0   1
-1/2  0  1/2

如果您不想处理分数,则将其乘以2即可得到著名的Sobel 3x3内核。

      -1 0 1
G_x = -2 0 2
      -1 0 1

乘以2仅用于获得方便的整数。多数情况下,无论如何,输出图像的缩放比例基本上都是任意的(无论如何,以得到清晰可见的结果)。

通过与上述相同的推理,您可以通过将相邻分量沿正y方向(0,1)投影到单位矢量上来获得垂直梯度gy的内核

      -1 -2 -1
G_y =  0  0  0
       1  2  1

任意大小的内核的公式

如果要使用5x5或更大的内核,则只需注意距离,例如

A B 2 B A
B C 1 C B
2 1 - 1 2
B C 1 C B
A B 2 B A

哪里

A = 2 * sqrt2
B = sqrt5
C = sqrt2.

如果连接任意两个像素的矢量的长度为L,则该方向上的单位矢量的系数为1 / L。因此,可以将任何像素“ k”对(例如)x梯度(1,0)的贡献简化为“(平方距离上的值差)乘以(非归一化方向向量“ ok”的点积与梯度向量,例如(1,0))”

gx_k = (k - o)/(pixel distance^2) ['ok' dot (1,0)].

因为连接向量与x单位向量的点积选择了相应的向量条目,所以位置k处的相应G_x内核条目为

i / (i*i + j*j)

其中i和j是从中心像素到像素k在x和y方向上的步数。在上述3x3计算中,像素“ a”的i = -1(左侧为1),j = -1(顶部为1),因此“ a”内核项为-1 /(1 + 1 )= -1/2。

G_y内核的条目是

j/(i*i + j*j). 

如果我想为内核提供整数值,请按照以下步骤操作:

  • 检查输出图像的可用范围
  • 通过应用浮点内核来计算可能的最高结果(即假设所有正内核条目下的最大输入值,因此输出值为(所有正内核值的总和)*(最大可能输入图像值)。如果对输入进行了签名,则需要同时考虑负值。最坏的情况是所有正值的总和+负条目的所有绝对值的总和(如果最大输入在正数下,-max输入在负数下)编辑:所有绝对值的总和为也被恰当地称为内核的权重
  • 计算内核允许的最大放大比例(没有输出图像的溢出范围)
  • 对于浮点内核的所有整数倍(从2到最大),检查绝对舍入误差的总和最低,并使用此内核

因此,总而言之:

Gx_ij = i / (i*i + j*j)
Gy_ij = j / (i*i + j*j)

i,j是内核中从中心算起的位置。根据需要缩放内核条目以获得整数(或至少近似)。

这些公式适用于所有内核大小。

例子

          -2/8 -1/5  0  1/5  2/8           -5  -4  0   4   5
          -2/5 -1/2  0  1/2  2/5           -8 -10  0  10   8
G_x (5x5) -2/4 -1/1  0  1/1  2/4  (*20) = -10 -20  0  20  10
          -2/5 -1/2  0  1/2  2/5           -8 -10  0  10   8
          -2/8 -1/5  0  1/5  2/8           -5  -4  0   4   5

请注意,以浮点数表示的5x5内核的中心3x3像素只是3x3内核,即,较大的内核代表使用其他但权重较低的数据的持续近似。这继续适用于更大的内核大小:

           -3/18 -2/13 -1/10 0  1/10 2/13 3/18
           -3/13 -2/8  -1/5  0  1/5  2/8  3/13
           -3/10 -2/5  -1/2  0  1/2  2/5  3/10
G_x (7x7)  -3/9  -2/4  -1/1  0  1/1  2/4  3/9 
           -3/10 -2/5  -1/2  0  1/2  2/5  3/10
           -3/13 -2/8  -1/5  0  1/5  2/8  3/13
           -3/18 -2/13 -1/10 0  1/10 2/13 3/18

此时,精确的整数表示形式变得不切实际。

据我所知(无法访问原始论文),“ Sobel”部分正在适当地加权贡献。可以通过省略距离权重并在内核中适当输入i和j来获得Prewitt解决方案。

奖励:索贝尔内核可任意指示

因此,我们可以近似估算图像梯度的x和y分量(实际上是矢量,正如开头所述)。可以通过将梯度矢量投影到alpha梯度单位矢量上来获得任意方向上的alpha梯度(在数学上为正,在这种情况下为顺时针,因为y为向下)。

alpha单位向量是(cos alpha,sin alpha)。对于alpha = 0°,可以获得gx的结果,对于alpha = 90°,则可获得gy。

g_alpha = (alpha-unit vector) dot (gx, gy)
        = (cos a, sin a) dot (gx, gy)
        = cos a * gx + sin a * gy

如果您不愿将gx和gy记为邻居贡献的总和,您会意识到可以将得出的长表达式按适用于同一邻居像素的术语进行分组,然后将其重写为带有条目的单个卷积核

G_alpha_ij = (i * cos a + j * sin a)/(i*i + j*j)

如果您想要最接近的整数近似值,请按照上面概述的步骤进行操作。

收藏
评论

更新2018年4月23日:似乎在下面的链接中定义的内核不是真正的Sobel内核(对于5x5及更高版本)-它们可能在边缘检测方面做得很合理,但是不应将它们称为Sobel内核。有关更准确,更全面的摘要,请参见Daniel的答案 。 (我将在此处保留此答案,因为(a)从各个地方链接到该答案,并且(b)无法轻易删除已接受的答案。)

Google似乎提供了很多结果,例如http://rsbweb.nih.gov/nih-image/download/user-macros/slowsobel.macro建议使用以下3x3、5x5、7x7和9x9内核:

3x3:

1   0   -1
2   0   -2
1   0   -1

5x5:

2   1   0   -1  -2
3   2   0   -2  -3
4   3   0   -3  -4
3   2   0   -2  -3
2   1   0   -1  -2

7x7:

3   2   1   0   -1  -2  -3
4   3   2   0   -2  -3  -4
5   4   3   0   -3  -4  -5
6   5   4   0   -4  -5  -6
5   4   3   0   -3  -4  -5
4   3   2   0   -2  -3  -4
3   2   1   0   -1  -2  -3

9x9:

4   3   2   1   0   -1  -2  -3  -4
5   4   3   2   0   -2  -3  -4  -5
6   5   4   3   0   -3  -4  -5  -6
7   6   5   4   0   -4  -5  -6  -7
8   7   6   5   0   -5  -6  -7  -8
7   6   5   4   0   -4  -5  -6  -7
6   5   4   3   0   -3  -4  -5  -6
5   4   3   2   0   -2  -3  -4  -5
4   3   2   1   0   -1  -2  -3  -4

收藏
评论

Sobel梯度滤波器生成器

(此答案是指上面@Daniel给出的分析 。)

Gx[i,j] = i / (i*i + j*j)

Gy[i,j] = j / (i*i + j*j)

原始论文相比,这是一个重要的结果,并且是一个更好的解释。应该将其写在Wikipedia或某处,因为它似乎也优于互联网上有关此问题的任何其他讨论。

但是,如要求保护的那样,对于大小大于5 * 5的过滤器,整数值表示实际上是不切实际的。使用64位整数,可以精确表示最大15 * 15的Sobel滤波器大小。

这是前四个;结果应除以“权重”,以便将如下图像区域的梯度归一化为值1。

1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5

Gx(3):

-1/2  0/1  1/2           -1  0  1
-1/1    0  1/1   * 2 =   -2  0  2
-1/2  0/1  1/2           -1  0  1

weight = 4               weight = 8

Gx(5):

-2/8 -1/5  0/4  1/5  2/8             -5  -4   0   4   5
-2/5 -1/2  0/1  1/2  2/5             -8 -10   0  10   8
-2/4 -1/1    0  1/1  2/4   * 20 =   -10 -20   0  20  10
-2/5 -1/2  0/1  1/2  2/5             -8 -10   0  10   8
-2/8 -1/5  0/4  1/5  2/8             -5  -4   0   4   5

weight = 12                          weight = 240

Gx(7):

-3/18 -2/13 -1/10   0/9  1/10  2/13  3/18             -130 -120  -78    0   78  120  130
-3/13  -2/8  -1/5   0/4   1/5   2/8  3/13             -180 -195 -156    0  156  195  180
-3/10  -2/5  -1/2   0/1   1/2   2/5  3/10             -234 -312 -390    0  390  312  234
 -3/9  -2/4  -1/1     0   1/1   2/4   3/9   * 780 =   -260 -390 -780    0  780  390  260
-3/10  -2/5  -1/2   0/1   1/2   2/5  3/10             -234 -312 -390    0  390  312  234
-3/13  -2/8  -1/5   0/4   1/5   2/8  3/13             -180 -195 -156    0  156  195  180
-3/18 -2/13 -1/10   0/9  1/10  2/13  3/18             -130 -120  -78    0   78  120  130

weight = 24                                           weight = 18720

Gx(9):

-4/32 -3/25 -2/20 -1/17  0/16  1/17  2/20  3/25  4/32                -16575  -15912  -13260   -7800       0    7800   13260   15912   16575
-4/25 -3/18 -2/13 -1/10   0/9  1/10  2/13  3/18  4/25                -21216  -22100  -20400  -13260       0   13260   20400   22100   21216
-4/20 -3/13  -2/8  -1/5   0/4   1/5   2/8  3/13  4/20                -26520  -30600  -33150  -26520       0   26520   33150   30600   26520
-4/17 -3/10  -2/5  -1/2   0/1   1/2   2/5  3/10  4/17                -31200  -39780  -53040  -66300       0   66300   53040   39780   31200
-4/16  -3/9  -2/4  -1/1     0   1/1   2/4   3/9  4/16   * 132600 =   -33150  -44200  -66300 -132600       0  132600   66300   44200   33150
-4/17 -3/10  -2/5  -1/2   0/1   1/2   2/5  3/10  4/17                -31200  -39780  -53040  -66300       0   66300   53040   39780   31200
-4/20 -3/13  -2/8  -1/5   0/4   1/5   2/8  3/13  4/20                -26520  -30600  -33150  -26520       0   26520   33150   30600   26520
-4/25 -3/18 -2/13 -1/10   0/9  1/10  2/13  3/18  4/25                -21216  -22100  -20400  -13260       0   13260   20400   22100   21216
-4/32 -3/25 -2/20 -1/17  0/16  1/17  2/20  3/25  4/32                -16575  -15912  -13260   -7800       0    7800   13260   15912   16575

weight = 40                                                          weight = 5304000

下面附加的Ruby程序将计算Sobel过滤器和任意大小的相应权重,尽管整数值过滤器对于大于15 * 15的大小不太可能有用。

#!/usr/bin/ruby

# Sobel image gradient filter generator
# by <ian_bruce@mail.ru> -- Sept 2017
# reference:
# https://stackoverflow.com/questions/9567882/sobel-filter-kernel-of-large-size


if (s = ARGV[0].to_i) < 3 || (s % 2) == 0
    $stderr.puts "invalid size"
    exit false
end

s /= 2


n = 1

# find least-common-multiple of all fractional denominators
(0..s).each { |j|
    (1..s).each { |i|
        d = i*i + j*j
        n = n.lcm(d / d.gcd(i))
    }
}


fw1 = format("%d/%d", s, 2*s*s).size + 2
fw2 = format("%d", n).size + 2


weight = 0
s1 = ""
s2 = ""

(-s..s).each { |y|
    (-s..s).each { |x|
        i, j = x, y   # "i, j = y, x" for transpose
        d = i*i + j*j
        if (i != 0)
            if (n * i % d) != 0   # this should never happen
                $stderr.puts "inexact division: #{n} * #{i} / ((#{i})^2 + (#{j})^2)"
                exit false
            end
            w = n * i / d
            weight += i * w
        else
            w = 0
        end
        s1 += "%*s" % [fw1, d > 0 ? "%d/%d" % [i, d] : "0"]
        s2 += "%*d" % [fw2, w]
    }
    s1 += "\n" ; s2 += "\n"
}


f = n.gcd(weight)

puts s1

puts "\nweight = %d%s" % [weight/f, f < n ? "/%d" % (n/f) : ""]

puts "\n* #{n} =\n\n"

puts s2

puts "\nweight = #{weight}"
收藏
评论

其他资料似乎对较大的内核给出了不同的定义。例如, 英特尔IPP库将5x5内核设置为

1  2 0  -2 -1
4  8 0  -8 -4
6 12 0 -12 -6
4  8 0  -8 -4
1  2 0  -2 -1

直观上,这对我来说更有意义,因为您将更多地关注靠近中心的元素。它在3x3内核方面也具有自然定义,可以轻松扩展以生成更大的内核。就是说,在我的简短搜索中,我发现了5x5内核的3种不同定义-因此,我怀疑(如Paul所说)较大的内核是临时的,因此这绝不是确定的答案。

3x3内核是平滑内核和渐变内核的外部乘积,在Matlab中,这类似于

sob3x3 = [ 1 2 1 ]' * [1 0 -1]

可以通过将3x3内核与另一个平滑内核进行卷积来定义较大的内核

sob5x5 = conv2( [ 1 2 1 ]' * [1 2 1], sob3x3 )

您可以重复此过程以逐渐获得更大的内核

sob7x7 = conv2( [ 1 2 1 ]' * [1 2 1], sob5x5 )
sob9x9 = conv2( [ 1 2 1 ]' * [1 2 1], sob7x7 )
...

还有很多其他方式可以编写它,但是我认为这可以很好地解释正在发生的事情。基本上,您从一个方向上的平滑内核开始,而在另一个方向上从导数的有限差分估计开始,然后仅应用平滑操作,直到获得所需的内核大小。

因为这只是一系列卷积,所以所有不错的属性(可交换性,关联性等)都可能对您的实现有用。例如,您可以将5x5内核分为其平滑分量和导数分量:

sob5x5 = conv([1 2 1],[1 2 1])' * conv([1 2 1],[-1 0 1])

请注意,为了成为“适当的”导数估计量,应将3x3 Sobel的比例缩放为1/8:

sob3x3 = 1/8 * [ 1 2 1 ]' * [1 0 -1]

并且每个较大的内核都需要按1/16的比例进行缩放(因为未对平滑内核进行标准化):

sob5x5 = 1/16 * conv2( [ 1 2 1 ]' * [1 2 1], sob3x3 )
sob7x7 = 1/16 * conv2( [ 1 2 1 ]' * [1 2 1], sob5x5 )
...
收藏
评论

这是使用numpy和@Daniel答案使用python 3制作的简单解决方案。

def custom_sobel(shape, axis):
    """
    shape must be odd: eg. (5,5)
    axis is the direction, with 0 to positive x and 1 to positive y
    """
    k = np.zeros(shape)
    p = [(j,i) for j in range(shape[0]) 
           for i in range(shape[1]) 
           if not (i == (shape[1] -1)/2. and j == (shape[0] -1)/2.)]

    for j, i in p:
        j_ = int(j - (shape[0] -1)/2.)
        i_ = int(i - (shape[1] -1)/2.)
        k[j,i] = (i_ if axis==0 else j_)/float(i_*i_ + j_*j_)
    return k

它返回内核(5,5),如下所示:

Sobel x:
   [[-0.25 -0.2   0.    0.2   0.25]
    [-0.4  -0.5   0.    0.5   0.4 ]
    [-0.5  -1.    0.    1.    0.5 ]
    [-0.4  -0.5   0.    0.5   0.4 ]
    [-0.25 -0.2   0.    0.2   0.25]]


Sobel y:
   [[-0.25 -0.4  -0.5  -0.4  -0.25]
    [-0.2  -0.5  -1.   -0.5  -0.2 ]
    [ 0.    0.    0.    0.    0.  ]
    [ 0.2   0.5   1.    0.5   0.2 ]
    [ 0.25  0.4   0.5   0.4   0.25]]

如果有人知道在python中执行此操作的更好方法,请告诉我。我是新手;)

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号