Быстрый метод удаления лишних точек в Matlab - PullRequest
0 голосов
/ 26 октября 2018

Я объединяю два объекта pointCloud в Matlab, скажем, pc1 и pc2. pc1 - это эталонное облако, то есть все точки из pc2, которые равны или очень близки к точкам из pc1, должны быть удалены до объединения облаков.

Разъяснения:

  • Я знаю функцию pcmerge, которая почти делает то, что я хочу, но мне определенно нужно удалить лишние точки, и усреднение этих точек не является опцией

  • Размер облака точек составляет около 500 000 каждый, и я должен сравнить многие (100) из них. Вот почему важна скорость.

  • Я бы предпочел иметь возможность определять радиус вокруг каждой точки pc1, чтобы дать критерий "избыточности". Но в пользу скорости, некоторые упрощения в порядке (см. Мой второй подход решения).

Подходы к решению:

  • Рабочее, но очень медленное решение - искать каждую точку в pc2 для ближайшего соседа:

    function [ pc ] = pcaddcloud( pc1, pc2, res )
    
    limits = overlapRange(pc2, pc1);
    pc1idx = findPointsInROI(pc2, limits);
    pc2Overlap = select(pc2, pc1idx);
    idx = findPointsInROI(pc1, limits);
    pc1Overlap = select(pc1, idx);
    endi = pc2Overlap.Count;
    pc2Overlap = pc2Overlap.Location;
    for i=1:endi
        [idx, ~] = findNeighborsInRadius(pc1Overlap, pc2Overlap(i,:), res);
        % keep only indices of redundant points to delete them later
        if isempty(idx)
            pc1idx(i) = 0;
        end
    end
    pc1idx(pc1idx==0) = [];
    pc2 = pc2.Location;
    pc2(pc1idx,:) = [];
    pc = pointCloud([pc1.Location; pc2]);
    end
    
    % Compute the bounding box of overlapped region (from pcmerge)
    function rangeLimits = overlapRange(pcA, pcB)
    xlimA = pcA.XLimits;
    ylimA = pcA.YLimits;
    zlimA = pcA.ZLimits;
    
    xlimB = pcB.XLimits;
    ylimB = pcB.YLimits;
    zlimB = pcB.ZLimits;
    
    if (xlimA(1) > xlimB(2) || xlimA(2) < xlimB(1) || ...
            ylimA(1) > ylimB(2) || ylimA(2) < ylimB(1) || ...
            zlimA(1) > zlimB(2) || zlimA(2) < zlimB(1))
        % No overlap
        rangeLimits = [];
    else
        rangeLimits = [ min(xlimA(1),xlimB(1)), max(xlimA(2),xlimB(2)); ...
            min(ylimA(1),ylimB(1)), max(ylimA(2),ylimB(2)); ...
            min(zlimA(1),zlimB(1)), max(zlimA(2),zlimB(2))];
    end
    end
    
  • У меня есть более быстрое решение (все еще медленное, но быстрее, чем решение 1), работающее с альфа-фигурами: я определяю оболочку вокруг pc1 и решаю, находятся ли точки pc2 внутри или нет. Недостаток: точки, которые только "немного снаружи" (то есть близко к точкам pc1, но не находятся внутри альфа-формы), не распознаются как избыточные.

    function [ pc ] = pcaddcloud( pc1, pc2 )
    
    limits = overlapRange(pc2, pc1);
    pc2 = pc2.Location;
    pc1 = pc1.Location;
    %seems to be faster than findPointsInROI:
    pc2Overlap = pc2(pc2(:,1)>=limits(1,1)&pc2(:,1)<=limits(1,2) ...
        &pc2(:,2)>=limits(2,1)&pc2(:,2)<=limits(2,2)...
        &pc2(:,3)>=limits(3,1)&pc2(:,3)<=limits(3,2),:);
    pc2idx = find(pc2(:,1)>=limits(1,1)&pc2(:,1)<=limits(1,2) ...
        &pc2(:,2)>=limits(2,1)&pc2(:,2)<=limits(2,2)...
        &pc2(:,3)>=limits(3,1)&pc2(:,3)<=limits(3,2));
    pc1Overlap = pc1(pc1(:,1)>=limits(1,1)&pc1(:,1)<=limits(1,2) ...
        &pc1(:,2)>=limits(2,1)&pc1(:,2)<=limits(2,2)...
        &pc1(:,3)>=limits(3,1)&pc1(:,3)<=limits(3,2),:);
    
    shape = alphaShape(double(pc1Overlap));
    in = inShape(shape, double(pc2Overlap));
    pc2idx(~in) = [];
    pc2(pc2idx,:) = [];
    pc = pointCloud([pc1; pc2]);
    
    end
    
    % Compute the bounding box of overlapped region (from pcmerge)
    function rangeLimits = overlapRange(pcA, pcB)
    xlimA = pcA.XLimits;
    ylimA = pcA.YLimits;
    zlimA = pcA.ZLimits;
    
    xlimB = pcB.XLimits;
    ylimB = pcB.YLimits;
    zlimB = pcB.ZLimits;
    
    if (xlimA(1) > xlimB(2) || xlimA(2) < xlimB(1) || ...
            ylimA(1) > ylimB(2) || ylimA(2) < ylimB(1) || ...
            zlimA(1) > zlimB(2) || zlimA(2) < zlimB(1))
        % No overlap
        rangeLimits = [];
    else
        rangeLimits = [ min(xlimA(1),xlimB(1)), max(xlimA(2),xlimB(2)); ...
            min(ylimA(1),ylimB(1)), max(ylimA(2),ylimB(2)); ...
            min(zlimA(1),zlimB(1)), max(zlimA(2),zlimB(2))];
    end
    end
    

Я с нетерпением жду ваших идей! Пожалуйста, не стесняйтесь спрашивать дополнительную информацию, если это необходимо - я новичок в этой платформе. Спасибо!

1 Ответ

0 голосов
/ 26 октября 2018

Вы можете использовать ismembertol с опцией ByRows для обнаружения избыточных точек. Но учтите, что вместо сферической окрестности он использует кубическую окрестность. Предполагая, что у вас есть две матрицы pc1, pc2 каждая имеет 3 столбца и допуск tol:

idx = ismembertol(pc2, pc1, tol,'ByRows', true, 'DataScale' , 1);
result = [pc1; pc2(~idx,:)];
...