File Exchange

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

Updated 26 Apr 2015

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

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:
[B,~,~,A] = bwboundaries(BW);
figure
subplot(1,2,1), imshow(BW), title('Original')

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)};
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:

### Cite As

April

Amazing. Thank you so much.

Monique

Nahid

Rui Venâncio

Johannes Schmitz

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);
- 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.')

Johannes Schmitz

Alessandro La Chioma

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:

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.

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