提高MATLAB逻辑索引性能

时间:2016-05-03 09:12:14

标签: performance matlab indexing

我正在研究一个函数,它从一个大坐标集中选择一条线周围的边界框内的所有点(以加快RANSAC拟合)。我昨晚运行了包含该功能的脚本,总共55k秒30k(在55M调用中)花费在这一行(X是3×N笛卡尔坐标,xmin,{{1}等等是与xmax和相应边界相同长度的向量:

X

你能帮助我加快速度吗?短路,这将是提高性能的良好开端,似乎不适用于索引。

或者如果有一个完全不同的更好的方法,这里是函数代码的其余部分(inlierIdx = ( X(1,:) >= xmin & X(1,:) <= xmax & X(2,:) >= ymin & X(2,:) <= ymax ); p1是定义该行的点,a是边界框的偏移量;额外的步骤需要另外12k秒才能进行55M通话):

p2

我刚刚发现我应该移动那个奇异的if子句,所以如果是真的则跳过计算,但这是次要的性能损失。

为每个RANSAC样本调用该函数,仅选择距离采样行合理距离的点,以计算它们的阈值距离。

MATLAB版本是R2016a。

并行计算工具箱可用,我尝试将步骤移动到arrayfuns并使用gpuArrays调用整个函数,但速度要慢一些。

整个背景如下:

function [inlierX, xmin, xmax, ymin, ymax] = selectbox(X, L, a) % xmin ... ymax only for plotting purposes
% X: 3xN coords to check; L: 3x2 vector defining line; a: offset of bounding box
p1 = L(:,1);
p2 = L(:,2);

constfactor = (X(3,:)-p1(3))/(p2(3)-p1(3)); % precompute for following steps
xmin = p1(1) + (p2(1)-p1(1))*constfactor - a; % line parallel to x-component of defined line, with offset
xmax = xmin + 2*a;
ymin = p1(2) + (p2(2)-p1(2))*constfactor - a;
ymax = ymin + 2*a; 

inlierIdx = ( X(1,:) >= xmin & X(1,:) <= xmax & X(2,:) >= ymin & X(2,:) <= ymax );

if p1(3) == p2(3) % singularity if line is horizontal, discard then
    inlierIdx = [];
end

inlierX = X(:,inlierIdx); % save & return inlier coordinates

我使用10k-100k点的数组,对于我想要拟合的每一行,我运行1E + 5 ... 1E + 6次试验以找到最佳设置。我有大约50行适合,我通过删除找到的行的内部并在剩余的上做算法来完成它们。

2 个答案:

答案 0 :(得分:1)

我怀疑这一行是真正的问题。你说你对这个函数做了5500万次调用 - 我们可以看到代码吗?因为我强烈怀疑这个代码是真正的问题所在。

我怀疑你在一个循环中调用这个函数,这将使MATLAB很难/不可能通过其JIT编译器有效地加速调用。如果是这种情况,那么实际上,显示的最重负担将是这一行,但它只是如此缓慢,因为您的代码结构迫使MATLAB继续调用解释器,而不是执行机器代码。如果确实如此,那么在循环体中就地复制粘贴这个小函数将极大地加快一切(即,如果循环体的其余部分也可以加速......)

无论如何,这是我能做到的。它以额外索引为代价减少了比较次数;我也怀疑这是否更快...哦,好吧,只需要进行1000次通话并进行比较。

function [inlierX, xmin, xmax, ymin, ymax] = selectbox(X, L, a)

    % X: 3xN coords to check; L: 3x2 vector defining line; a: offset of bounding box
    p1 = L(:,1);
    p2 = L(:,2);

    constfactor = (X(3,:)-p1(3)) / (p2(3)-p1(3));

    % line parallel to x-component of defined line, with offset
    xmin = p1(1) + (p2(1)-p1(1))*constfactor - a; 
    xmax = xmin + 2*a;
    ymin = p1(2) + (p2(2)-p1(2))*constfactor - a;
    ymax = ymin + 2*a;

    % singularity if line is horizontal, discard then
    if p1(3) ~= p2(3)        
        inlierIdx            = X(1,:)         >= xmin;        
        inlierIdx(inlierIdx) = X(1,inlierIdx) <= xmax(inlierIdx);
        inlierIdx(inlierIdx) = X(2,inlierIdx) >= ymin(inlierIdx);
        inlierIdx(inlierIdx) = X(2,inlierIdx) <= ymax(inlierIdx);                
    else
        inlierIdx = [];
    end

    inlierX = X(:,inlierIdx); % save & return inlier coordinates

end

答案 1 :(得分:1)

如何在代码中使用列式索引?我的意思是使用X作为Nx3笛卡尔坐标而不是3xN。到目前为止,据我所知,由于MATLAB数组以FORTRAN方式存储,因此列式索引可以更快。