关于可分离卷积的This article 应该会澄清一点。
我最近不得不这样做,所以这里是:作为示例,我们使用基于标准差为 0.85 的二维高斯分布的内核。我们需要一个 3x3 内核(Matlab 代码)。
>> h = fspecial('gaussian',3,0.85)
h =
0.0626 0.1250 0.0626
0.1250 0.2497 0.1250
0.0626 0.1250 0.0626
请注意,所有条目的总和为 1,即如果将其用作过滤器,图像的亮度不会改变:
>> sum(sum(h))
ans =
1
还要注意rank 为 1,因此内核实际上是可分离的(两个向量 h1 和 h2 相乘时将得到 h:h1*h2=h)
>> rank(h)
ans =
1
太好了,我们可以继续了。请注意,如果排名大于 1,您仍然可以获得近似值,但您可能需要使用不同的技术(请参阅最后的链接)。
在不深入细节的情况下,我们使用svd 函数执行singular value decomposition。这是一个标准函数,计算 U*S*V'=h 并且在许多数学库中都可用。
>> [U,S,V] = svd(h)
U =
-0.4085 0.9116 -0.0445
-0.8162 -0.3867 -0.4292
-0.4085 -0.1390 0.9021
S =
0.3749 0 0
0 0.0000 0
0 0 0.0000
V =
-0.4085 -0.3497 -0.8431
-0.8162 0.5534 0.1660
-0.4085 -0.7559 0.5115
我们现在知道U*S*V'=h(V' 是V 的转置)。现在,对于秩为 1 的矩阵,S 应该只有 1 个奇异值,其余的应该是 0(有关更多信息,请参阅此答案末尾的讨论)。
所以我们现在需要的是(h1)*(h2)=h。我们可以将S 拆分为两个不同的值,这样s1*s2=S。因此我们得到:U*s1*s2*V'=h,然后是(U*s1)*(s2*V')=h。
您可以根据需要选择如何拆分S,但使用平方根会将S 在h1 和h2 之间平分:
>> h1 = U*sqrt(S)
h1 =
-0.2501 0.0000 -0.0000
-0.4997 -0.0000 -0.0000
-0.2501 -0.0000 0.0000
>> h2 = sqrt(S)*V'
h2 =
-0.2501 -0.4997 -0.2501
-0.0000 0.0000 -0.0000
-0.0000 0.0000 0.0000
请注意,我们不需要带零的额外行/列,因此我们可以像这样更简单:
>> h1 = U(:,1)*sqrt(S(1,1))
h1 =
-0.2501
-0.4997
-0.2501
>> h2 = sqrt(S(1,1))*V(:,1)'
h2 =
-0.2501 -0.4997 -0.2501
请注意,减号相互抵消,因此您也可以根据需要将它们从 h1 和 h2 中删除:
h1 =
0.2501
0.4997
0.2501
h2 =
0.2501 0.4997 0.2501
>> h1*h2
ans =
0.0626 0.1250 0.0626
0.1250 0.2497 0.1250
0.0626 0.1250 0.0626
这与我们之前的(几乎)相同:
>> h1*h2 - h
ans =
1.0e-16 *
0 0.2776 -0.1388
0 0.5551 -0.2776
0 0.2776 -0.1388
请注意,机器精度 eps 只是:
>> eps
ans =
2.2204e-16
所以错误很小,在这种情况下是由于不精确造成的。如果您有任何比这大得多的错误,您很可能只是忽略了剩余的奇异值并计算了h 的 rank-1 近似值。在这种情况下,您可能需要查看其他选项以获得更好的近似值,例如this implementation 或 this implementation。