MATLAB中的双求和与矢量化循环

MATLAB中的双求和与矢量化循环,matlab,optimization,for-loop,sum,vectorization,Matlab,Optimization,For Loop,Sum,Vectorization,下面是我在实现这个可爱公式方面的尝试 如您所见,外部两个循环用于滑动窗口,而其余内部循环用于求和变量 现在,我对我亲爱的stackoverflow用户的要求是:您能帮我改进这些非常讨厌的for循环,它们占用的时间超过了它的份额,并将其转化为矢量化循环吗? 这一改进是否会带来重大变化 谢谢。这可能不是你要问的,但是(乍一看)似乎总和的顺序是独立的,你可以用{l,k,x,y}代替{x,y,l,k}。这样做可以使内核保持在最外层的循环中,从而减少计算内核的次数。这四个嵌套循环基本上是以滑动邻域方式处

下面是我在实现这个可爱公式方面的尝试

如您所见,外部两个循环用于滑动窗口,而其余内部循环用于求和变量

现在,我对我亲爱的stackoverflow用户的要求是:您能帮我改进这些非常讨厌的for循环,它们占用的时间超过了它的份额,并将其转化为矢量化循环吗? 这一改进是否会带来重大变化


谢谢。

这可能不是你要问的,但是(乍一看)似乎总和的顺序是独立的,你可以用{l,k,x,y}代替{x,y,l,k}。这样做可以使内核保持在最外层的循环中,从而减少计算内核的次数。

这四个嵌套循环基本上是以滑动邻域方式处理图像中的每个像素。我立刻想到了它的功能

下面是我对代码矢量化的尝试。请注意,我还没有完全测试它,也没有将性能与基于循环的解决方案进行比较:

function WD = wigner(D, Md, Nd, lambda)
    %# window size and lambda
    if nargin<2, Md = 5; end
    if nargin<3, Nd = 5; end
    if nargin<4, lambda = 5; end

    %# image size
    [M,N,~] = size(D);

    %# kernel = exp(-lambda*norm([k,l])
    [K,L] = meshgrid(-floor(Md/2):floor(Md/2), -floor(Nd/2):floor(Nd/2));
    K = K(:); L = L(:);
    kernel = exp(-lambda .* sqrt(K.^2+L.^2));

    %# frequency-domain part
    F = fft2(D);

    %# f(x+k,y+l) * f(x-k,y-l) * kernel
    C = im2col(D, [Md Nd], 'sliding');
    X1 = bsxfun(@times, C .* flipud(C), kernel);

    %# cos(theta)
    C = im2col(F, [Md Nd], 'sliding');
    C = C(round(Md*Nd/2),:);    %# take center pixels
    theta = bsxfun(@times, real(C), K/M) + bsxfun(@times, imag(C), L/N);
    X2 = cos(4*pi*theta);

    %# combine both parts for each sliding-neighborhood
    WD = col2im(sum(X1.*X2,1), [Md Nd], size(F), 'sliding') .* (4/(M*N));

    %# pad array with zeros to be of same size as input image
    WD = padarray(WD, ([Md Nd]-1)./2, 0, 'both');
end

然后,您可能需要缩放/规范化矩阵,并应用阈值…

我想您将看到
M
N
的大值的改进。它们有多大?我可以告诉你矢量化肯定会提高计算速度。当MATLAB做矢量数学时,它会一直到你的电脑进行优化。@EitanT图像尺寸是320(N)x240(M)。我建议你看一下。@EitanT我看了你发布的链接。到目前为止,我把所有的循环都转换成网格;但是我遇到了范数函数的问题。我希望它使用矩阵的元素,而不是整个矩阵,即范数(K,L);式中[L,K]=网格(-floor(Nd/2):floor(Nd/2),-floor(Md/2):floor(Md/2));这是一个极好的建议;功能得到了极大的改善。我向你致敬。+1代表劳伯515@Absi,如果你认为这个答案是有帮助的(即使你不认为它是你问题的完整答案),你至少应该按向上箭头向上投票(▲).@我确实试图提高自己的声誉;不幸的是,我需要拥有15的声誉。我向劳伯特515道歉。@Absi哦,好吧,我没有注意你的声誉。我向你道歉,先生:)@EitanT没关系,伙计,谢谢你花时间帮我:)嘿,阿姆罗。首先,谢谢你的辛勤工作。第二,我在运行函数时遇到这个错误:-???使用==>重塑来重塑元素的数量时出错,不得更改。错误==>col2im在84 a=重塑(b,垫(1)-块(1)+1,垫(2)-块(2)+1);在29 WD=col2im(和(X1.*X2,1),[Md Nd],大小(F),“滑动”)时,wignerVector中的错误*(4/(M*N));“@Absi:你确定你在处理灰度图像吗?如果在此之前不调用RGB2GRAY..是的,我是肯定的。这是一个示例,我将此图像与之后的图像的差异发送给wigner。@Absi:实际上,它是一个RGB图像,即使所有通道都相等(
ndims(img)==3
)。你需要调用RGB2GRAY…啊,这是正确的。现在它似乎正在工作。非常感谢兄弟。不过我有一个问题要问你:当使用外值乘以二次求和(即4/(MN))时,图像会变黑。我已将其更改为4/(MdNd),它显示了一个很好的结果。你有什么不太清楚的想法吗?
function WD = wigner(D, Md, Nd, lambda)
    %# window size and lambda
    if nargin<2, Md = 5; end
    if nargin<3, Nd = 5; end
    if nargin<4, lambda = 5; end

    %# image size
    [M,N,~] = size(D);

    %# kernel = exp(-lambda*norm([k,l])
    [K,L] = meshgrid(-floor(Md/2):floor(Md/2), -floor(Nd/2):floor(Nd/2));
    K = K(:); L = L(:);
    kernel = exp(-lambda .* sqrt(K.^2+L.^2));

    %# frequency-domain part
    F = fft2(D);

    %# f(x+k,y+l) * f(x-k,y-l) * kernel
    C = im2col(D, [Md Nd], 'sliding');
    X1 = bsxfun(@times, C .* flipud(C), kernel);

    %# cos(theta)
    C = im2col(F, [Md Nd], 'sliding');
    C = C(round(Md*Nd/2),:);    %# take center pixels
    theta = bsxfun(@times, real(C), K/M) + bsxfun(@times, imag(C), L/N);
    X2 = cos(4*pi*theta);

    %# combine both parts for each sliding-neighborhood
    WD = col2im(sum(X1.*X2,1), [Md Nd], size(F), 'sliding') .* (4/(M*N));

    %# pad array with zeros to be of same size as input image
    WD = padarray(WD, ([Md Nd]-1)./2, 0, 'both');
end
function WD = wigner_loop(D, Md, Nd, lambda)
    %# window size and lambda
    if nargin<2, Md = 5; end
    if nargin<3, Nd = 5; end
    if nargin<4, lambda = 5; end

    %# image size
    [M,N,~] = size(D);

    %# frequency-domain part
    F = fft2(D);

    WD = zeros([M,N]);
    for l = -floor(Nd/2):floor(Nd/2)
        for k = -floor(Md/2):floor(Md/2)
            %# kernel = exp(-lambda*norm([k,l])
            kernel = exp(-lambda * norm([k,l]));

            for x = (1+floor(Md/2)):(M-floor(Md/2))
                for y = (1+floor(Nd/2)):(N-floor(Nd/2))
                    %# cos(theta)
                    theta = 4 * pi * ( real(F(x,y))*k/M + imag(F(x,y))*l/N );

                    %# f(x+k,y+l) * f(x-k,y-l)* kernel
                    WD(x,y) = WD(x,y) + ( cos(theta) * D(x+k,y+l) * D(x-k,y-l) * kernel );
                end
            end
        end
    end
    WD = WD * ( 4/(M*N) );
end
%# difference between two consecutive frames
A = imread('AT3_1m4_02.tif');
B = imread('AT3_1m4_03.tif');
D = imsubtract(A,B);
%#D = rgb2gray(D);
D = im2double(D);

%# apply Wigner-Distribution
tic, WD1 = wigner(D); toc
tic, WD2 = wigner_loop(D); toc
figure(1), imshow(WD1,[])
figure(2), imshow(WD2,[])