我在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
这部分代码还很慢......
答案 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))
然后您可以按cX
和c(1)
cY
替换c(2)
,再次消除对round
另外,我认为不需要使用
cX < size(S,2) && cX > 1 && cY < size(S,1) && cY > 1
自size(S,2)=W
和size(S,1)=H
最后,由于matlab的方式,列向量比行向量快一些,因此将lIR
和lIC
更改为列可以为您节省一些额外的秒数。
我认为这可以帮助你稍微提高代码的速度,但它不会给你一个与矢量化一样好的加速。
问题是我似乎无法想出一种方法来正确地向量化该块的行为
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。