如何优化从3D矩阵生成线性索引的matlab函数

时间:2013-04-03 22:30:25

标签: matlab optimization vectorization mathematical-optimization

我在MATLAB中编写了一小段代码。这实际上是从3D矩阵制作线性索引的函数。这实际上是一个更大项目的一部分。问题是代码工作但它没有优化,而且速度很慢。当我在MATLAB上运行探查器时,此功能消耗了90%的计算时间。我该如何优化此代码?

%
A = rand(3,3);
H = 1200;
W = 1500;
S = rand(H,W,3,'uint8')
R = zeros(H,W,3,'uint8');
lIR = zeros(1,H*W*3);
lIC = zeros(1,H*W*3);
count = 0;
for rY = 1:1:H
    for rX = 1:1:W
        [oX,oY] = func1(rX,rY);
        cP = A*[oX; oY; 1];
        cP = cP / cP(3);
        cX = round(cP(1)); cY = round(cP(2));
        if cX < size(S,2) && cX > 1 && cY < size(S,1) && cY > 1
            lIR(count+1:count+3) = sub2ind([size(R) 1],[rY rY rY], [rX rX rX],1:3);
            lIC(count+1:count+3) = sub2ind([size(S) 1],[cY cY cY],[cX cX cX],1:3);
            count = count + 3;
        end
    end
end
%
function [oX,oY] = func1(rX,rY)
C1 = 1000;
C2 = 1200;
C3 = 1500;
C4 = 1700;
oX = C1 + (C3 - C1) * ((rX - 1) / (W - 1));
oY = C2 + (C4 - C2) * ((rY - 1) / (H - 1));
end

(更新)好的,我从循环中取出了函数,现在这部分是使用向量计算,这样更快

[rX,rY] = meshgrid(1:W,1:H);
[oX,oY] = func1(rX,rY);

现在代码如下:

%
A = rand(3,3);
H = 1200;
W = 1500;
S = rand(H,W,3,'uint8')
R = zeros(H,W,3,'uint8');
lIR = zeros(1,H*W*3);
lIC = zeros(1,H*W*3);
count = 0;
[rX,rY] = meshgrid(1:W,1:H);
[oX,oY] = func1(rX,rY);

for j = 1:1:H
    for i = 1:1:W

        cP = A*[oX(i); oY(j); 1];
        cP = cP / cP(3);
        c = round(cP);
        if cp(1) < size(S,2) && cp(1) > 1 && cp(2) < size(S,1) && cp(2) > 1
            lIR(count+1:count+3) = sub2ind([size(R) 1],[rY rY rY], [rX rX rX],1:3);
            lIC(count+1:count+3) = sub2ind([size(S) 1],[cY cY cY],[cX cX cX],1:3);
            count = count + 3;
        end
    end
end
%
function [oX,oY] = func1(rX,rY)
C1 = 1000;
C2 = 1200;
C3 = 1500;
C4 = 1700;
oX = C1 + (C3 - C1) * ((rX - 1) / (W - 1));
oY = C2 + (C4 - C2) * ((rY - 1) / (H - 1));
end

此外,我尝试制作内部函数的优化版本,sub2ind:

function ndx = sub2ind_optimized(siz,varargin)
siz = double(siz);
numOfIndInput = nargin-1;
k = [1 siz(1) siz(1)*siz(2)];
ndx = 1;
for i = 1:numOfIndInput
    v = varargin{i};
    ndx = ndx + (v-1)*k(i);
end

这部分代码还很慢......

3 个答案:

答案 0 :(得分:2)

只需使用sub2ind - 一个将下标转换为线性索引的内置函数。

linearInd = sub2ind(arraySize, dim1Sub, dim2Sub, dim3Sub, ...)返回大小为arraySize的N维数组的每个维度的指定下标的线性索引等价物。 arraySize输入是一个n元素向量,用于指定数组中的维数。 dimNSub输入是正数,整数标量或向量,用于指定矩阵的一个或多个行列下标。

例如,

A = rand(3, 4, 2);
linearInd = sub2ind(size(A), 2, 1, 2);

linearInd =
14

答案 1 :(得分:1)

优化此代码的最佳方法是对其进行矢量化,但我现在似乎无法弄清楚如何做到这一点,但是,我看到一些可以优化的事情可能会给你一个小的加速,第一,行

[oX,oY] = func1(rX,rY);

可以从循环中取出并更新func1以生成两个矩阵[oX(ry,rj)]和[oY(ry,rj)],然后您只需访问值而不是再次调用func1,这将消除对func1几乎1.800.000次调用所消耗的时间,同时消耗大约30 MB的内存(我在matlab中创建了一个1200x1500随机矩阵,它在14.4左右出现) MB)。

同样,行

cX = round(cP(1)); cY = round(cP(2));

可能只是

c=round(CP(1:2))

然后您可以按cXc(1) cY替换c(2),再次消除对round

的近1.800.000次呼叫

另外,我认为不需要使用

cX < size(S,2) && cX > 1 && cY < size(S,1) && cY > 1

size(S,2)=Wsize(S,1)=H

以来

最后,由于matlab的方式,列向量比行向量快一些,因此将lIRlIC更改为列可以为您节省一些额外的秒数。

我认为这可以帮助你稍微提高代码的速度,但它不会给你一个与矢量化一样好的加速。

问题是我似乎无法想出一种方法来正确地向量化该块的行为

    if cX < size(S,2) && cX > 1 && cY < size(S,1) && cY > 1
        lIR(count+1:count+3) = sub2ind([size(R) 1],[rY rY rY], [rX rX rX],1:3);
        lIC(count+1:count+3) = sub2ind([size(S) 1],[cY cY cY],[cX cX cX],1:3);
        count = count + 3;
    end

如果我有任何新想法,我明天会更新,我现在真的需要睡觉。

干杯

答案 2 :(得分:0)

对于一个你可以摆脱func1。您可以通过

替换它
for ox = C1:(  (C3-C1)/(W-1) ):C3

oy是类似的。

实际上我想知道在if条件中增加计数器是否是错误。因此,lIR和lIC中的位置取决于结果。 它也是唯一取决于之前循环运行的值 - 如果你摆脱了这种依赖性,那么循环就可以用于parfor。