File Exchange

image thumbnail

mpoly2mask - convert multiple polygons to a mask

version 1.2.0.0 (6.17 KB) by Sven
Converts an object with multiple boundary contours to a logical mask

8 Downloads

Updated 26 Apr 2015

View License

MPOLY2MASK Convert multiple region-of-interest polygons to a mask.
BW = mpoly2mask(XY, BWSIZE) computes a binary region-of-interest mask,
BW, from multiple region-of-interest polygons represented by XY. The size
of BW (in rows, columns) is given in the 2-element BWSIZE. The class of
BW is logical with 1 inside the set of XY polygons and 0 outside.
XY is a cell array with separate polygon (xy) coordinates given as an
N-by-2 array in each cell element. Alternatively, XY can be an N-by-2
array containing all polygon coordinates, with each successive polygon
separated by a pair of NaN elements. By default, the output mask is the
union (mask1 & mask2 & ...) of all separate polygons.

BW = mpoly2mask(..., 'style','ij') will interpret the input given in XY
as being IJ-style contours rather than XY-style. This is consistent with
MATLAB's bwboundaries command which returns contours in ij format (row
coordinates in the first column, column coordinates in the second).

BW = mpoly2mask(XY, XVEC, YVEC) where XVEC and YVEC are vectors,
specifies the locations of the pixel centers of BW

BW = mpoly2mask(XY, ..., A) allows complex relationships between the
contours in XY. A is a square logical matrix with side length equal to
the number of contours in XY, whose rows and columns correspond to each
separate contour in XY. The boundaries *enclosed* by the (i)th contour,
or the boundary *enclosing* the i(th) contour can both be found using A
as follows:

enclosing_boundary = find(A(i,:));
enclosed_boundaries = find(A(:,i));

For example, a donut shape can be represented by two circular contours in
XY (XY{1} being the larger contour, X{2} being the smaller, and A having
contents:

A = [0 0
1 0]

Here, A(2,1) indicates that the second circle in XY is enclosed by the
first. A may be sparse, as created by the command sparse(2,1,true,2,2).
The logical matrix A can be ommited, in which case it defaults to a fully
false matrix indicating no enclosing contours, and the contents of BW
will be the union of all contours in XY.

Example 1:
BW = imread('blobs.png');
[B,~,~,A] = bwboundaries(BW);
BW2 = mpoly2mask(B,size(BW),A,'style','ij');
figure
subplot(1,2,1), imshow(BW), title('Original')
subplot(1,2,2), imshow(BW2), title('mpoly2mask recreation')

Example 2:
% Define polygon vertices
xyPts = {
[-90 -60; -10 40; 50 -50] ... A triangle (object 1)
[-80 -80; -80 20; 30 20; 30 -80]}; ... A square (object 2)};
% Define mask pixel locations
xVec = -150:150;
yVec = -100:50;
% Define different connectivity styles between polygons
[A,B] = deal(false(2));
A(1,2) = 1; % The first object is removed from the second
B(2,1) = 1; % The second object is removed from the first
BW = mpoly2mask(xyPts, xVec, yVec); % Union all objects
BW_A = mpoly2mask(xyPts, xVec, yVec, A);
BW_B = mpoly2mask(xyPts, xVec, yVec, B);
% Diisplay
figure
subplot(1,3,1), imagesc(xVec,yVec,BW), axis image, title 'Union'
subplot(1,3,2), imagesc(xVec,yVec,BW_A), axis image, title 'Connectivity A'
subplot(1,3,3), imagesc(xVec,yVec,BW_B), axis image, title 'Connectivity B'

Note that masks with contours extracted using bwboundaries that are then
directly passed to poly2mask (as in the first example) may have 1-pixel
border regions that do not match. This issue, including a simple
work-around is discussed at:
http://blogs.mathworks.com/steve/2014/03/27/comparing-the-geometries-of-bwboundaries-and-poly2mask/

Cite As

Sven (2019). mpoly2mask - convert multiple polygons to a mask (https://www.mathworks.com/matlabcentral/fileexchange/46428-mpoly2mask-convert-multiple-polygons-to-a-mask), MATLAB Central File Exchange. Retrieved .

Comments and Ratings (9)

April

Amazing. Thank you so much.

Monique

Nahid

I changed this to fix for different resolutions:

@@ -147,11 +147,13 @@ if length(varargin)==1 && length(varargin{1})==2
elseif length(varargin)==2 && isvector(varargin{1}) && isvector(varargin{2})
xVec = varargin{1};
yVec = varargin{2};
- m = length(yVec);
- n = length(xVec);
+ resolution_x = xVec(2)-xVec(1);
+ resolution_y = yVec(2)-yVec(1);
+ m = round(max(yVec)/resolution_y);
+ n = round(max(xVec)/resolution_x);
pMaskFcn = @(xy)poly2mask(...
- interp1(xVec, 1:n, xy(:,XYcols(1)),'linear','extrap'),...
- interp1(yVec, 1:m, xy(:,XYcols(2)),'linear','extrap'),...
+ xy(:,XYcols(1)),...
+ xy(:,XYcols(2)),...
m, n);
else
error('mpoly2mask:input','input parameters could not be resolved.')

Useful for me as well. Thank you very much for uploading.

Alessandro

Very useful code.

Something that might be introduced:
similarly to the built-in poly2mask, if you have a single contour delimiting a region already delimited by the same contour, that overlapping region will be excluded my the mask:
https://www.mathworks.com/matlabcentral/answers/195603-overlapping-region-of-a-single-roi-is-excluded-by-the-mask

Chad Greene

I second Craig's comment. I needed to create a 9000x9000 land/ocean mask from outlines of several thousand islands. Some island outlines contain over a million coordinate pairs. In my first attempt, I used a loop to create a mask for each island using Matlab's poly2mask, then planned to let the final mask be the logical of the sum of all my masks. However, my loop did not finish overnight. Using mpoly2mask, the mask was complete within minutes.

Thanks for writing this excellent utility, Sven, thank you for sharing it on FEX, and thank you for writing coherent documentation with a simple working example.

Craig

Thanks very much Sven for a very useful code. I'm using it to convert polygons from shapefiles into raster masks for extracting pixels from GeoTIFF files. mpoly2mask is about 100 times faster than anything I came up with.

Updates

1.2.0.0

More descriptive title text

1.1.0.0

Made a little more robust to zero/one connectivity matrix instead of logical mask. Added extra help example.

MATLAB Release Compatibility
Created with R2014a
Compatible with any release
Platform Compatibility
Windows macOS Linux