Matlab:向量化4个嵌套for循环

时间:2017-02-09 05:17:53

标签: matlab vectorization

所以,我需要将一些for循环向量化为一行。我理解如何矢量化一个和两个for循环,但我真的很难做更多。本质上,我正在计算尺寸为nxm的原始矩阵M的大小(n-2)x(m-2)的“模糊”矩阵M2,其中s = size(M):

for x = 0:1
    for y = 0:1
        m =  zeros(1, 9);
        k = 1;
        for i = 1:(s(1) - 1)
            for j = 1:(s(2) - 1)
                m(1, k) = M(i+x,j+y);
                k = k+1;
            end
        end
    M2(x+1,y+1) = mean(m);
    end
end

这是我最接近的:

for x=0:1
    for y=0:1
        M2(x+1, y+1) = mean(mean(M((x+1):(3+x),(y+1):(3+y))))
    end
end

为了更接近单线解决方案,似乎必须存在某种“通信”,我将两个变量(x,y)分配给M2 索引的索引超过M;我只是不知道如何做到这一点,但我确信有一个解决方案。

1 个答案:

答案 0 :(得分:3)

您是否有理由不使用MATLAB的卷积功能来帮助您这样做?使用具有重叠邻域的3 x 3平均内核进行模糊处理。这正是卷积正在做的事情。您可以使用conv2执行此操作:

M2 = conv2(M, ones(3) / 9, 'valid');

'valid'标记可确保您按照要求在两个维度中返回size(M) - 2矩阵。

在您的代码中,您已将其硬编码为4 x 4矩阵。要仔细检查我们是否有正确的结果,让我们生成一个随机的4 x 4矩阵:

rng(123);
M = rand(4, 4);
s = size(M);

如果我们使用您的代码运行此代码,我们会得到:

>> M2

M2 =

    0.5054    0.4707
    0.5130    0.5276

使用conv2

执行此操作
>> M2 = conv2(M, ones(3) / 9, 'valid')

M2 =

    0.5054    0.4707
    0.5130    0.5276

但是,如果你想从第一原理做到这一点,那么像素邻域的重叠很难用循环来逃避。你拥有的两个for循环方法已经足够好了,它可以恰当地解决问题。我会输入输入的大小而不是硬编码。因此,编写一个类似这样的函数:

function M2 = blur_fp(M)
s = size(M);
M2 = zeros(s(1) - 2, s(2) - 2);
for ii = 2 : s(1) - 1
    for jj = 2 : s(2) - 1
        p = M(ii - 1 : ii + 1, jj - 1 : jj + 1);
        M2(ii - 1, jj - 1) = mean(p(:));
    end
end

第一行代码定义了函数,我们将其称为blur_fp。接下来的几行代码确定输入矩阵的大小以及初始化空白矩阵以存储输出。然后我们循环遍历矩阵中的每个像素位置,而内核不会超出图像边界,我们抓住一个3 x 3邻域,每个像素位置作为中心,然后我们展开将矩阵转换为单列向量,找到平均值并将其存储在适当的输出中。对于小内核和相对较大的矩阵,这应该执行正常。

为了更进一步,您可以使用用户Divakarim2col_sliding函数,该函数将重叠的邻域并将它们展开到列中。因此,每列代表一个邻域,然后您可以使用向量矩阵乘法模糊输入。然后,您可以使用reshape将结果重新整形为矩阵:

T = im2col_sliding(M, [3 3]);
V = ones(1, 9) / 9;
s = size(M);
M2 = reshape(V * T, s(1) - 2, s(2) - 2);

遗憾的是,除非您使用内置函数,否则无法在一行中完成。我不确定你的意图是什么,但希望你在这里看到的各种方法能让你对如何有效地做到这一点有所了解。 BTW,使用小矩阵(即4×4)的循环可能效率更高。当你增加输入的大小时,你会开始注意到性能的变化......然后,我认为当JIT显着改善时,使用循环是有竞争力的,因为R2015b。