【问题标题】:Double Summation in MATLAB and vectorized loopsMATLAB 和矢量化循环中的双重求和
【发布时间】:2012-05-25 17:36:19
【问题描述】:

这是我实现这个可爱公式的尝试。

http://dl.dropbox.com/u/7348856/Picture1.png

%WIGNER Computes Wigner-Distribution on an image (difference of two images).
function[wd] = wigner(difference)
%Image size
[M, N, ~] = size(difference);
%Window size (5 x 5)
Md = 5;
Nd = 5;
%Fourier Transform
F = fft2(difference);
%Initializing the wigner picture
wd = zeros(M, N, 'uint8');
lambda =0.02;
value = (4/(Md*Nd));
for x = 1+floor(Md/2):M - floor(Md/2)
    for y = 1+floor(Nd/2):N - floor(Nd/2)
        for l = -floor(Nd/2) : floor(Nd/2)
            for k = -floor(Md/2) : floor(Md/2)
                kernel = exp(-lambda * norm(k,l));
                kernel = kernel * value;
                theta = 4 * pi * ((real(F(x, y)) * (k/M) )+ (imag(F(x, y)) * (l/N)));
                wd(x, y) = (wd(x, y)) + (cos(theta) * difference(x + k, y + l) * difference(x - k, y - l) * (kernel));
            end
        end
    end
end
end

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

现在,亲爱的 stackoverflow 用户,我对您的请求是:您能帮我改进这些非常讨厌的 for 循环,这些循环花费的时间超过其份额,并将其变成矢量化循环吗? 这种改进会带来重大变化吗?

谢谢。

【问题讨论】:

  • 我想你会看到 MN 的大值的改进。它们有多大?
  • 我可以告诉你矢量化肯定会提高计算速度。当 MATLAB 进行矢量数学运算时,它会一直向下传递到您 PC 的 BLAS 以进行优化。
  • @EitanT 图片尺寸为 320(N) x 240(M)。
  • 我建议你看看this question
  • @EitanT 我查看了您发布的链接。到目前为止,我将所有循环都转换为网格网格;但我遇到了规范函数的问题。我希望它使用矩阵的元素而不是整个矩阵,即 norm(K, L);其中 [L,K] = meshgrid(-floor(Nd/2):floor(Nd/2), -floor(Md/2):floor(Md/2));

标签: matlab optimization for-loop sum vectorization


【解决方案1】:

这可能不是您要问的,但似乎(乍一看)求和的顺序是独立的,您可以用 {l,k,x 代替 {x,y,l,k} ,y}。这样做可以让您通过将内核保持在最外层循环中来减少对内核的评估次数。

【讨论】:

  • 这是一个绝妙的建议;功能提升到了非同寻常的程度。我向你致敬。
  • Laurbert515 的 +1。 @Absi,如果您认为此答案有帮助(即使您不认为它是您问题的完整答案),您至少应该按向上箭头 (▲) 对其进行投票。
  • @EitanT 我确实尝试过投票;不幸的是,我需要有 15 的声誉。我向 Laubert515 道歉。
  • @Absi 哦,好吧,我没注意你的声望值。先生,我向你道歉:)
  • @EitanT 没关系,谢谢你花时间帮助我 :)
【解决方案2】:

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

这是我对代码进行矢量化的尝试。请注意,我尚未对其进行彻底测试,或将性能与基于循环的解决方案进行比较:

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

对于它的价值,这里是基于循环的版本,具有@Laurbert515 建议的改进:

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

以及我如何测试它(基于我从paperpreviously 链接到的内容):

%# 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,[])

然后您可能需要对矩阵进行缩放/归一化,并应用阈值...

【讨论】:

  • 嘿阿姆罗。首先,感谢辛勤工作。其次,当我运行该函数时出现此错误:- ???错误使用 ==> 重塑要重塑元素的数量不得改变。 ==> col2im 在 84 处出错 a = reshape(b,mat(1)-block(1)+1,mat(2)-block(2)+1); ==> wignerVector 在 29 WD = col2im(sum(X1.*X2,1), [Md Nd], size(F), 'sliding') .* (4/(M*N));"
  • @Absi:你确定你在处理灰度图像吗?如果在此之前不调用 RGB2GRAY..
  • 是的,我很肯定。这是一个示例dl.dropbox.com/u/7348856/img_00003.bmp 我将这张图片和它之后的图片的差异发送给 wigner。
  • @Absi:实际上它是一个 RGB 图像,即使所有通道都是相等的 (ndims(img)==3)。你需要调用RGB2GRAY...
  • 嗯,没错。现在它似乎正在工作。谢谢一百万兄弟。不过我有一个问题要问你;当使用乘以双重求和的外部值(即 4/(MN))时,图像变成漆黑。我已将其更改为 4/(MdNd),它显示了一个很好的结果。你知道为什么吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多