Matlab去除多余点的快速方法
Fast method to remove redundant points in Matlab
我在 Matlab 中合并了两个点云对象,比方说 pc1 和 pc2。 pc1 是参考云,即 pc2 中与 pc1 中的点相等或非常接近的所有点都需要在组合云之前移除。
说明:
我知道函数 pcmerge
,它几乎可以满足我的要求 - 但我绝对需要删除多余的点并且对这些点进行平均不是一个选项
每个点云大小约为500,000个,我必须比较其中的许多(100个)。这就是为什么速度很重要。
我希望能够在 pc1 的每个点周围定义一个半径来给出 "being redundant" 的标准。但是为了提高速度,可以进行一些简化(参见我的第二种解决方法)。
解决方法:
一个可行但非常慢的解决方案是在 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 更快)使用 alpha 形状:我在 pc1 周围定义一个外壳并决定 pc2 的点是否在里面。缺点:只有 "slightly outside" 的点(即靠近 pc1 的点但不在 alpha 形状内)不会被检测为冗余。
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
期待您的想法!如果需要,请随时询问更多信息 - 我是这个平台的新手。谢谢!
您可以使用 ismembertol
和 ByRows
选项来检测冗余点。但是请考虑它使用立方体邻域而不是球形邻域。
假设您有两个矩阵 pc1
,pc2
每个都有 3 列和一个公差 tol
:
idx = ismembertol(pc2, pc1, tol,'ByRows', true, 'DataScale' , 1);
result = [pc1; pc2(~idx,:)];
我在 Matlab 中合并了两个点云对象,比方说 pc1 和 pc2。 pc1 是参考云,即 pc2 中与 pc1 中的点相等或非常接近的所有点都需要在组合云之前移除。
说明:
我知道函数
pcmerge
,它几乎可以满足我的要求 - 但我绝对需要删除多余的点并且对这些点进行平均不是一个选项每个点云大小约为500,000个,我必须比较其中的许多(100个)。这就是为什么速度很重要。
我希望能够在 pc1 的每个点周围定义一个半径来给出 "being redundant" 的标准。但是为了提高速度,可以进行一些简化(参见我的第二种解决方法)。
解决方法:
一个可行但非常慢的解决方案是在 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 更快)使用 alpha 形状:我在 pc1 周围定义一个外壳并决定 pc2 的点是否在里面。缺点:只有 "slightly outside" 的点(即靠近 pc1 的点但不在 alpha 形状内)不会被检测为冗余。
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
期待您的想法!如果需要,请随时询问更多信息 - 我是这个平台的新手。谢谢!
您可以使用 ismembertol
和 ByRows
选项来检测冗余点。但是请考虑它使用立方体邻域而不是球形邻域。
假设您有两个矩阵 pc1
,pc2
每个都有 3 列和一个公差 tol
:
idx = ismembertol(pc2, pc1, tol,'ByRows', true, 'DataScale' , 1);
result = [pc1; pc2(~idx,:)];