我试图减少一组点上图像的双线性插值处理时间。首先,我做了一个正常的循环。因为我已经在调用interp的函数上使用了parfor,所以我无法使用parfor。我试图对函数进行矢量化,它可以工作,但处理时间几乎没有减少。
Any ideas of how can I improve the vectorized version?
一些结果:
编辑 - 结果之前变化很大。我不知道为什么,但现在它们一致,价值观也没有太大变化。
我添加了tmirt2D,因为@ Dev-iL指出了它。他的代码比我的快得多(约3倍),他使用的是C ++。
Interp 2D tester
Time for each point and speed up in '%' based on the reference time.
Array size: 10000. Repeat: 10. Loops: 20
Normal for loop interp: 145.6354 ns (reference time)
Vect interp (in bounds): 68.6679 ns (112.09%)
Vect interp (out boudns): 66.5793 ns (118.74%)
Vect interp nearest (in boudns): 28.2870 ns (414.85%)
Vect interp nearest (out boudns): 26.3854 ns (451.95%)
tmirt2D from File Exchange: 22.6089 ns (544.15%)
Matlab interp2 linear: 921.0408 ns (-84.19%)
Matlab interp2 nearest: 911.7492 ns (-84.03%)
测试代码:
clearvars; clc; close all;
mustCompareMatlab = 1;
tm1 = 0;
tm2 = 0;
tm3 = 0;
tm4 = 0;
tm5 = 0;
tm6 = 0;
tm7 = 0;
tmirt2D = 0;
baseLoopN = 10;
for j=1:baseLoopN
%% Create data
dataSize = [1200 1600];
data = rand(dataSize)*255;
N = 1e4;
X = rand(1,N)*dataSize(2);
Y = rand(1,N)*dataSize(1);
% Only inside bounds-1 coordinates
Xin = X(X<dataSize(2)-1);
Yin = Y(Y<dataSize(1)-1);
% make X and Y same size
Xin(end+1:length(X)) = ones(1,length(X)-length(Xin));
Yin(end+1:length(X)) = ones(1,length(X)-length(Yin));
% Make sure X and Y have outside bounds values
X(1) = dataSize(2) + 1;
Y(1) = dataSize(1) + 1;
loops = 20;
% Catch
interpData = Interp2D(data,X,Y);
tic
for i=1:loops
interpData = Interp2D(data,X,Y);
end
tm1 = tm1 + toc;
%% Only inside bounds coordinates
% Catch
interpData = Interp2DVect(data,Xin,Yin);
tic
for i=1:loops
interpData = Interp2DVect(data,Xin,Yin);
end
tm2 = tm2 + toc;
%% inside and outside bounds
% Catch
interpData = Interp2DVect(data,X,Y);
tic
for i=1:loops
interpDataInterp2DVect = Interp2DVect(data,X,Y);
end
tm3 = tm3 + toc;
%% inside bounds nearest
% Catch
interpData = Interp2DNearest(data,Xin,Yin);
tic
for i=1:loops
interpData = Interp2DNearest(data,Xin,Yin);
end
tm4 = tm4 + toc;
%% inside and outside bounds nearest
% Catch
interpData = Interp2DNearest(data,X,Y);
tic
for i=1:loops
interpData = Interp2DNearest(data,X,Y);
end
tm5 = tm5 + toc;
% mirt2D_mexinterp
% www.mathworks.com/matlabcentral/fileexchange/24183-2d-interpolation
interpData = mirt2D_mexinterp(data,X,Y);
tic
for i=1:loops
interpDataMirt2D = mirt2D_mexinterp(data,X,Y);
end
tmirt2D = tmirt2D + toc;
%% Matlab interp
if mustCompareMatlab
interpData = interp2(data,X,Y,'linear'); %#ok<*NASGU>
tic
for i=1:loops
interpData = interp2(data,Xin,Yin,'linear');
end
tm6 = tm6 + toc;
interpData = interp2(data,X,Y,'nearest');
tic
for i=1:loops
interpData = interp2(data,Xin,Yin,'nearest');
end
tm7 = tm7 + toc;
end
%%
end
A = interpDataInterp2DVect;
B = interpDataMirt2D;
C = A-B;
fprintf('Interp 2D tester\n');
fprintf('Array size: %d. Repeat: %d. Loops: %d\n',N,baseLoopN,loops);
tm1 = tm1*1e9/(baseLoopN*loops*N);
fprintf('Normal for loop interp: %.4f ns\n',tm1);
tm2 = tm2*1e9/(baseLoopN*loops*N);
fprintf('Vect interp (in bounds): %.4f ns (%.2f%%)\n',tm2,100*(tm1/tm2-1));
tm3 = tm3*1e9/(baseLoopN*loops*N);
fprintf('Vect interp (out boudns): %.4f ns (%.2f%%)\n',tm3,100*(tm1/tm3-1));
tm4 = tm4*1e9/(baseLoopN*loops*N);
fprintf('Vect interp nearest (in boudns): %.4f ns (%.2f%%)\n',tm4,100*(tm1/tm4-1));
tm5 = tm5*1e9/(baseLoopN*loops*N);
fprintf('Vect interp nearest (out boudns): %.4f ns (%.2f%%)\n',tm5,100*(tm1/tm5-1));
tmirt2D = tmirt2D*1e9/(baseLoopN*loops*N);
fprintf('tmirt2D from File Exchange: %.4f ns (%.2f%%)\n',tmirt2D,100*(tm1/tmirt2D-1));
if mustCompareMatlab
tm6 = tm6*1e9/(baseLoopN*loops*N);
fprintf('Matlab interp2 linear: %.4f ns (%.2f%%)\n',tm6,100*(tm1/tm6-1));
tm7 = tm7*1e9/(baseLoopN*loops*N);
fprintf('Matlab interp2 nearest: %.4f ns (%.2f%%)\n',tm7,100*(tm1/tm7-1));
end
普通版:
function [interpData] = Interp2D(data,X,Y)
[sizY, sizX] = size(data);
interpData =zeros(1,length(X),'like',X);
for item=1:length(X),
valX=floor(X(item));
valY=floor(Y(item));
valYp1=valY+1;
valXp1=valX+1;
if (sizY < valYp1)||(sizX < valXp1)|| valX<=0 || valY<=0
interpData(item)=NaN;
else
Inten00=data(valY,valX);
Inten10=data(valY,valXp1);
Inten01=data(valYp1,valX);
Inten11=data(valYp1,valXp1);
px=(X(item))-valX;
py=(Y(item))-valY;
interpData(item)=((1-px)*Inten00+px*Inten10)*(1-py)+((1-px)*Inten01+px*Inten11)*py;
end
end
矢量化版本:
% Images borders are disconsidered due to simplicity
function [interpData,outBounds] = Interp2DVect(data,X,Y)
[sizeY, sizeX] = size(data);
fX = floor(X);
fY = floor(Y);
sizeOkFlag = ~((sizeY-1 < fY)|(sizeX-1 < fX)| fX <= 0 | fY <= 0);
sizeAllOk = min(sizeOkFlag) >= 1;
outBounds = ~sizeAllOk;
% If we have some invalid points, lets set them to NaN
if ~sizeAllOk
interpData = nan(1,length(X),'like',X);
% Prevent invalid data indexes
fX = fX(sizeOkFlag);
fY = fY(sizeOkFlag);
X = X(sizeOkFlag);
Y = Y(sizeOkFlag);
end
pX = X - fX;
pY = Y - fY;
% We need to get the linear indexes
% www.mathworks.com/company/newsletters/articles/matrix-indexing-in-matlab.html
%ids00 = sub2ind(dataSize, fY, fX);
% A fast replacement for sub2ind
% http://tipstrickshowtos.blogspot.com.br/2010/02/fast-replacement-for-sub2ind.html
%idsYX
ids00 = fY + (fX-1).*sizeY;
ids01 = fY + (fX).*sizeY;
ids10 = fY+1 + (fX-1).*sizeY;
ids11 = fY+1 + fX.*sizeY;
if sizeAllOk
interpData = ((1-pX).*data(ids00) + pX.*data(ids01)).*(1-pY) + ...
((1-pX).*data(ids10) + pX.*data(ids11)).*pY;
else
interpData(sizeOkFlag) = ((1-pX).*data(ids00) + pX.*data(ids01)).*(1-pY) + ...
((1-pX).*data(ids10) + pX.*data(ids11)).*pY;
if (size(X,1) > 1)
interpData = interpData';
end
end
最近的版本(仅供比较)
function [interpData] = Interp2DNearest(data,X,Y)
[sizeY, sizeX] = size(data);
X = round(X);
Y = round(Y);
sizeOkFlag = ~((sizeY-1 < Y)|(sizeX-1 < X)| X <= 0 | Y <= 0);
% Slower if use this:
%sizeAllOk = min(sizeOkFlag) >= 1;
% if sizeAllOk
% ids = Y + (X-1).*sizeY;
% interpData = data(ids);
% else
interpData = nan(1,length(X),'like',X);
X = X(sizeOkFlag);
Y = Y(sizeOkFlag);
ids = Y + (X-1).*sizeY;
interpData(sizeOkFlag) = data(ids);