Aar*_*kan 39 image-processing computer-vision edge-detection sobel
我正在使用尺寸为3x3的索贝尔滤波器来计算图像导数.看一下互联网上的一些文章,似乎sobel过滤器的大小为5x5和7x7的内核也很常见,但我无法找到它们的内核值.
有人可以让我知道尺寸为5x5和7x7的sobel滤波器的内核值吗?此外,如果有人可以共享一个方法来生成内核值,那将非常有用.
提前致谢.
Ada*_*wen 36
其他来源似乎给出了较大内核的不同定义.例如,英特尔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
Run Code Online (Sandbox Code Playgroud)
直观地说,这对我来说更有意义,因为你更关注靠近中心的元素.它还具有3x3内核的自然定义,易于扩展以生成更大的内核.也就是说,在我的简短搜索中,我发现了5x5内核的3种不同定义 - 所以我怀疑(正如保罗所说)较大的内核是临时的,所以这绝不是明确的答案.
3x3内核是平滑内核和渐变内核的外积,在Matlab中就是这样的
sob3x3 = [ 1 2 1 ]' * [1 0 -1]
Run Code Online (Sandbox Code Playgroud)
可以通过将3x3内核与另一个平滑内核进行卷积来定义更大的内核
sob5x5 = conv2( [ 1 2 1 ]' * [1 2 1], sob3x3 )
Run Code Online (Sandbox Code Playgroud)
您可以重复此过程以逐渐获得更大的内核
sob7x7 = conv2( [ 1 2 1 ]' * [1 2 1], sob5x5 )
sob9x9 = conv2( [ 1 2 1 ]' * [1 2 1], sob7x7 )
...
Run Code Online (Sandbox Code Playgroud)
还有很多其他的写作方式,但我认为这可以准确地解释发生了什么.基本上,你从一个方向的平滑内核和另一个方向的导数的有限差分估计开始,然后只应用平滑直到你得到你想要的内核大小.
因为它只是一系列卷积,所有好的属性都有,(交换性,关联性等)可能对你的实现有用.例如,您可以将5x5内核简单地分离为其平滑和衍生组件:
sob5x5 = conv([1 2 1],[1 2 1])'*conv([1 2 1],[ - 1 0 1])
请注意,为了成为"适当的"导数估计器,3x3 Sobel应缩放1/8倍:
sob5x5 = conv([1 2 1],[1 2 1])' * conv([1 2 1],[-1 0 1])
Run Code Online (Sandbox Code Playgroud)
每个较大的内核需要通过1/16的额外因子进行缩放(因为平滑内核未规范化):
sob3x3 = 1/8 * [ 1 2 1 ]' * [1 0 -1]
Run Code Online (Sandbox Code Playgroud)
Dan*_*iel 27
tl; dr:跳到"示例"部分
要添加另一个解决方案,请扩展此文档(它不是特别高质量,但它显示了从第2页底部开始的一些可用的图形和矩阵).
我们要做的是估计位置(x,y)处图像的局部梯度.梯度是由x和y方向上的分量,gx和gy组成的矢量.
现在,假设我们想要基于像素(x,y)及其邻居作为内核操作(3x3,5x5或任何大小)来近似渐变.
我们可以通过将所有相邻中心对的投影求和到梯度方向上来近似梯度.(Sobel的核心只是加权不同贡献的一种特殊方法,基本上也是Prewitt).
这是局部图像,中心像素(x,y)标记为"o"(中心)
a b c
d o f
g h i
Run Code Online (Sandbox Code Playgroud)
假设我们想要正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 ...
Run Code Online (Sandbox Code Playgroud)
编辑澄清:由于以下原因,有两个因素为1/sqrt(2):
我们感兴趣的是在特定方向(此处为x)对梯度的贡献,因此我们需要将从中心像素到相邻像素的方向梯度投影到我们感兴趣的方向上.这是通过采用标量积来实现的.在各个方向上的单位矢量,其引入第一因子1/L(这里对角线为1/sqrt(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
Run Code Online (Sandbox Code Playgroud)
现在是第一个对角线:
{(c-o)/sqrt2 * 1/sqrt2} + {(g-o)/sqrt2 * -1/sqrt2}
= (c - o)/2 - (g - o)/2
= (c - g)/2
Run Code Online (Sandbox Code Playgroud)
第二对角线贡献(i-a)/ 2.垂直方向贡献为零.请注意,来自中心像素"o"的所有贡献都消失了.
我们现在已经计算了所有最接近的邻居在像素(x,y)处的正x方向上对梯度的贡献,因此我们在x方向上的梯度的总近似值就是它们的总和:
gx(x,y) = f - d + (c - g)/2 + (i - a)/2
Run Code Online (Sandbox Code Playgroud)
我们可以通过使用卷积核获得相同的结果,其中系数被写在相应的相邻像素的位置:
-1/2 0 1/2
-1 0 1
-1/2 0 1/2
Run Code Online (Sandbox Code Playgroud)
如果您不想处理分数,则将其乘以2并获得众所周知的Sobel 3x3内核.
-1 0 1
G_x = -2 0 2
-1 0 1
Run Code Online (Sandbox Code Playgroud)
乘以2只能得到方便的整数.输出图像的缩放基本上是任意的,无论如何,大多数时候将其标准化为图像范围(以获得清晰可见的结果).
通过与上述相同的推理,通过将相邻贡献投影到正y方向(0,1)的单位向量上,得到垂直梯度gy的内核.
-1 -2 -1
G_y = 0 0 0
1 2 1
Run Code Online (Sandbox Code Playgroud)
如果你想要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
Run Code Online (Sandbox Code Playgroud)
哪里
A = 2 * sqrt2
B = sqrt5
C = sqrt2.
Run Code Online (Sandbox Code Playgroud)
如果连接任意两个像素的矢量的长度是L,则该方向上的单位矢量具有1/L的前因子.由于这个原因,任何像素'k'对(比如)x-梯度(1,0)的贡献可以简化为"(平均距离上的值差)"(非标准化方向矢量'ok'的DotProduct与梯度向量) ,例如(1,0))"
gx_k = (k - o)/(pixel distance^2) ['ok' dot (1,0)].
Run Code Online (Sandbox Code Playgroud)
因为连接向量与x单位向量的点积选择相应的向量条目,所以位置k处的相应G_x内核条目只是
i / (i*i + j*j)
Run Code Online (Sandbox Code Playgroud)
其中i和j是在x和y方向上从中心像素到像素k的步数.在上面的3x3计算中,像素'a'将具有i = -1(左边的1),j = -1(1到顶部),因此'a'内核条目是-1 /(1 + 1) )= -1/2.
G_y内核的条目是
j/(i*i + j*j).
Run Code Online (Sandbox Code Playgroud)
如果我想要内核的整数值,我按照以下步骤操作:
总结如下:
Gx_ij = i / (i*i + j*j)
Gy_ij = j / (i*i + j*j)
Run Code Online (Sandbox Code Playgroud)
其中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
Run Code Online (Sandbox Code Playgroud)
请注意,浮动表示法中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
Run Code Online (Sandbox Code Playgroud)
此时,精确的整数表示变得不切实际.
据我所知(无法访问原始论文),"索贝尔"部分对此做出了适当的贡献.Prewitt解决方案可以通过省略距离加权并在适当的时候在内核中输入i和j来获得.
因此,我们可以近似图像渐变的x和y分量(实际上是一个矢量,如最开始所述).可以通过将梯度向量投影到α梯度单位向量上来获得任意方向α(在数学上为正,在这种情况下顺时针,因为正y向下)的梯度.
α单位向量是(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
Run Code Online (Sandbox Code Playgroud)
如果您懒得将gx和gy写为邻居贡献的总和,您会发现可以通过适用于同一邻居像素的术语对结果长表达式进行分组,然后将其重写为带有条目的单个卷积内核
G_alpha_ij = (i * cos a + j * sin a)/(i*i + j*j)
Run Code Online (Sandbox Code Playgroud)
如果您想要最接近的整数近似值,请按照上面列出的步骤操作.
Pau*_*l R 15
更新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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
为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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
(这个答案参考了上面@Daniel 给出的分析。)
Gx[i,j] = i / (i*i + j*j)
Gy[i,j] = j / (i*i + j*j)
Run Code Online (Sandbox Code Playgroud)
这是一个重要的结果,也是比原始论文更好的解释。它应该写在维基百科或其他地方,因为它似乎也优于互联网上有关该问题的任何其他讨论。
然而,正如所声称的那样,整数值表示对于大小大于 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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
下面附加的 Ruby 程序将计算任何大小的 Sobel 滤波器和相应的权重,尽管整数值滤波器对于大于 15*15 的大小不太可能有用。
Gx[i,j] = i / (i*i + j*j)
Gy[i,j] = j / (i*i + j*j)
Run Code Online (Sandbox Code Playgroud)
这是使用 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
Run Code Online (Sandbox Code Playgroud)
它像这样返回内核(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]]
Run Code Online (Sandbox Code Playgroud)
如果有人知道在 python 中执行此操作的更好方法,请告诉我。我还是个新手 ;)