如何减少Hartley变换的for循环?

时间:2015-12-14 20:44:49

标签: performance matlab image-processing fft vectorization

我目前正致力于2D Hartley变换。代码如下所示:

for u=1:size(img,1)
    for v=1:size(img,2)
        for x=1:size(img,1)
            for y=1:size(img,2)
                a = 2*pi*u*x/size(img,1);
                b = 2*pi*v*y/size(img,2);
                temp= img(x,y)*(cos(a+b) + sin(a+b));
                X(u,v)= X(u,v)+temp;
            end
        end
    end
end

它有4个for循环,执行它需要很长时间。有没有什么方法可以通过减少for循环的数量来提高效率?任何与此相关的内容都会非常有用。

用于此2-D Hartley变换的公式如下所示: enter image description here

参考:Andrew B. Watson和Allen Poirson的可分离的二维离散Hartley变换。

3 个答案:

答案 0 :(得分:3)

如果你可以适应内存,你可以使用bsxfun一些额外的单身尺寸:

N = size(img,1);
M = size(img,2);
x = [1:N].'; %' vector of size N x 1 ( x 1 x 1)
y = 1:M;     %  vector of size 1 x M ( x 1 x 1)
u = permute(1:N,[1 3 2]); %vector of size 1 x 1 x N ( x 1)
v = permute(1:M,[1 3 4 2]); %vector of size 1 x 1 x 1 x M

a = 2*pi/N*bsxfun(@times,u,x); % N x 1 x N x 1
b = 2*pi/M*bsxfun(@times,v,y); % 1 x M x 1 x M
apb = bsxfun(@plus,a,b); % N x M x N x M
%img is N x M (x 1 x 1)

X2 = squeeze(sum(sum(bsxfun(@times,img,cos(apb)+sin(apb)),1),2));

不可否认,这是一种非常强大的力量,人们可能会提出一种更节省内存的解决方案。该解决方案大量使用每个数组隐含拥有无限数量的尾随单例维度,我在评论中试着注意到这一点。

使用N=20; M=30; img=rand(N,M);与原始循环版本进行比较:

>> max(max(abs(X-X2)))
ans =
     1.023181539494544e-12
>> max(max(abs(X)))
ans =
     3.091143465722029e+02

这意味着他们在机器精度范围内提供相同的解决方案。

答案 1 :(得分:3)

Andras和Divakar几乎提出了我在写作过程中采用的相同方法。因此,这个答案将简单地为您提供一种加速使用规范实现的方法。

您可以通过手动指定跨越图像范围的ndgrid空间坐标来消除使用forx作为变量的嵌套y循环对。此外,等式中的变换从 0 开始索引,但您的代码从1开始。您需要使用MATLAB开始索引为1,但计算等式中的项,您需要从0开始。因此,当您计算ab时,您必须从xyu和{中减去1 {1}}。

在任何情况下,您都可以计算元素方面的产品并将所有值相加。 预先分配输出效率也是一个好主意:

v

您希望能够获得更好的性能提升。将此与安德拉斯或迪瓦卡的解决方案进行比较,看看您对使用哪种解决方案感到满意。

答案 2 :(得分:3)

此处使用bsxfunfast matrix-multiplication进行矢量化解决方案 -

%// Store size parameters
[m,n] = size(img);

%// Get vectorized versions of a and b
A = 2*pi*(1:m).'*(1:m)/m;
B = 2*pi*(1:n).'*(1:n)/n;

%// Add vectorized a and b's to form a 4D array. Get cos + sin version.
AB = bsxfun(@plus,permute(A,[1 3 2 4]),permute(B,[3 1 4 2]));
cosAB = cos(AB) + sin(AB);

%// Finally bring in magic of matrix-multiplication for final output
Xout = reshape(img(:).'*reshape(cosAB,m*n,[]),m,n);