如何使用行和列上的 1D 卷积来计算 2D 卷积?

问题描述 投票:0回答:1

我正在寻找一种方法,通过在 Matlab 中使用

conv2
来计算
conv
给出的相同结果。 (我正在用 C 代码进行卷积,我需要比较 Matlab 和我的代码之间的结果)。

我听说只有当核

K
是可分离的(例如高斯核)时,才可以使用 1D 卷积向量乘法来获得与 2D 卷积矩阵乘法相同的结果。此外,通过这种方式,1D-way 比计算 2D-way 快得多。

这里我收集了一些Matlab代码

% Create data
A = randn(10, 10);

% Create gaussian kernel
sigma = 1;
kernel_size = round(6 * sigma);

% Create mesh grid
[x, y] = meshgrid(-kernel_size:kernel_size, -kernel_size:kernel_size);

% Create gaussian 2D kernel
K = 1/(2*pi*sigma^2)*exp(-(x.^2 + y.^2)/(2*sigma^2));

我想知道如果我只使用

conv2(A, K, 'same')
,我如何才能达到与
conv
相同的结果。我应该先对每一行执行
conv(A(i, :); K(i, :), 'same')
,然后对每列执行
conv(A(:, i); K(:, i), 'same')
吗?

matlab image-processing kernel convolution gaussian
1个回答
0
投票

如果 2-D 核

K
可分为行向量
kr
和列向量
kc
,使得
K = kc*kr
,则可以更有效地获得
conv2(A, K, 'same')
的结果,如
conv2(kr, kc, A, 'same')
(或等价)如
conv2(kc, kr, A, 'same')
)。

如果您只需要使用

conv
,则必须将
A
的每一行与
kr
进行卷积,然后将结果的每一列与
kc
进行卷积(或等效地以相反的顺序)。

所以,在你的例子中:

A = randn(10, 10);
sigma = 1;
kernel_size = round(6 * sigma);
[x, y] = meshgrid(-kernel_size:kernel_size, -kernel_size:kernel_size);
K = 1/(2*pi*sigma^2)*exp(-(x.^2 + y.^2)/(2*sigma^2));

result = conv2(A, K, 'same');

您可以获得相同的结果

x = -kernel_size:kernel_size;
y = x.';
kr = 1/sqrt(2*pi)/sigma * exp(-x.^2/(2*sigma^2));
kc = 1/sqrt(2*pi)/sigma * exp(-y.^2/(2*sigma^2));

result_sep = NaN(size(A));
for r = 1:size(A,1)
    result_sep(r,:) = conv(A(r,:), kr, 'same');
end
for c = 1:size(A,1)
    result_sep(:,c) = conv(result_sep(:,c), kc, 'same');
end

检查:

max(max(abs(result-result_sep)))

给出了

eps
量级的值,因此两个结果在浮点误差范围内是相同的。

© www.soinside.com 2019 - 2024. All rights reserved.