Alphashape boundary detection not working as desired

13 views (last 30 days)
Given a complex set of (x, y) data I would like to create a hull that is not convex but not fully conforming. I (think I) prefer alphashape over boundary as the former lets me select a specific number of pixels for the radius. My final goal is to create a mask from the outline of the resulting shape. However, my attempt has failed.
Any; suggestions on how to make this work as intended?
load XY.mat
shp = alphaShape(x, y, 100, 'HoleThreshold', 99999999999999);
[~, BXY] = boundaryFacets(shp);
figure
scatter(x, y, '.k')
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
figure
plot(shp)
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
% This looks good. I want everything green/black in the final mask.
figure
plot(BXY(:,1), BXY(:,2))
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
% This seems to have the correct points, but there are lines both
% inside and outside of the desired shape and for it to work right it
% needs to be just the outside boarder of the above
figure
BW = poly2mask(BXY(:,1), BXY(:,2), max(x) + 500, max(y) + 500);
imshow(BW);
% Consequently, the mask looks all wrong.
% I want the mask to to be the entire area enclosed by the alphashape,
% with no holes, and just the area enclosed by the alphashape.
  1 Comment
James Akula
James Akula on 23 Jun 2023
Closer. But still need help...
load XY.mat
shp = alphaShape(x, y, 100, 'HoleThreshold', 99999999999999);
[~, BXY] = boundaryFacets(shp);
subplot(2, 2, 1)
scatter(x, y, '.k')
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
subplot(2, 2, 2)
plot(shp)
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
% This looks good
subplot(2, 2, 3)
plot(BXY(:,1), BXY(:,2))
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
% This looks good, except there are crisscrossing lines and for it to work
% right it needs to be just the outside boarder
subplot(2, 2, 4)
[R, C] = find(ones([max(y) + 500, max(x)+500]));
tf = inShape(shp, C, R);
BW = false([max(y) + 500, max(x) + 500]);
BW(tf) = true;
imshow(BW)
% I was ablt to solve part of my problem--that is, the creation of a
% working mask. But I would still like the border plot (lower left) to
% work, too!

Sign in to comment.

Accepted Answer

James Akula
James Akula on 27 Jun 2023
An answer that seems to work is to convert the alphashape into a triangulation and then use "boundaryshape."
load XY.mat
shp = alphaShape(x, y, 100, 'HoleThreshold', 99999999999999);
subplot(2, 2, 1)
scatter(x, y, '.k')
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
subplot(2, 2, 2)
plot(shp)
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
subplot(2, 2, 3)
[tri, P] = alphaTriangulation(shp);
TR = triangulation(tri, P);
polyshp = boundaryshape(TR);
plot(polyshp, 'EdgeColor', 'b', 'FaceColor', 'none')
axis ij equal off
axis([1, max(x) + 500, 1, max(y) + 500])
subplot(2, 2, 4)
ps_regions = regions(polyshp);
BW = false([max(y) + 500, max(x) + 500]);
for ii = 1:numel(ps_regions)
BW = BW | poly2mask(...
ps_regions(ii).Vertices(:,1), ps_regions(ii).Vertices(:,2), ...
max(y) + 500, max(x) + 500);
end
imshow(BW)

More Answers (2)

Image Analyst
Image Analyst on 23 Jun 2023
Try imfill
BW = imfill(BW, 'holes');
  1 Comment
James Akula
James Akula on 23 Jun 2023
Thank you for this advice, but filling the holes isn't the solution, as that would do "too much." The "outline" of the blue plot does not match that of the alphashape, as lines crisscross both internally and externally.

Sign in to comment.


Matt J
Matt J on 23 Jun 2023
Edited: Matt J on 27 Jun 2023
Try bwlalphaclose() from this FEX submission,
load XY
s=5;
x=round(x/s)+10; y=round(y/s); %cut down to more manageable sizes
shp = alphaShape(x,y, 100/s, 'HoleThreshold', 99999999999999/s);
Warning: Duplicate data points have been detected and removed.
BW = accumarray([y,x], true, [max(y) + 500/s, max(x) + 500/s]);
BW=bwlalphaclose(BW,shp);
imshow(BW,[]); shg
hold on
scatter(x,y,'r.')
hold off
  3 Comments
Matt J
Matt J on 27 Jun 2023
Edited: Matt J on 27 Jun 2023
Here's what I get:
load XY
s=5;
x=round(x/s)+10; y=round(y/s); %cut down to more manageable sizes
shp = alphaShape(x,y, 100/s, 'HoleThreshold', 99999999999999/s);
Warning: Duplicate data points have been detected and removed.
BW = accumarray([y,x], true, [max(y) + 500/s, max(x) + 500/s]);
BW=bwlalphaclose(BW,shp);
imshow(BW,[]); shg
hold on
scatter(x,y,'r.')
hold off

Sign in to comment.

Categories

Find more on Bounding Regions in Help Center and File Exchange

Products


Release

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!