Serious problem with "createMask" function.

3 views (last 30 days)
Dear all,
I am trying to develop a tool that lets the user to correct manually the contour of an object. The idea is to convert each pixel in the contour and make it a vertex using "impoly" in following code:
Z = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];
BW = im2bw(Z);
B = bwboundaries(BW);
b = B{1};
X = b(:, 1);
Y = b(:, 2);
figure, imshow(BW);
hpoly = impoly(gca,[Y, X]);
wait (hpoly)
maskImage = hpoly.createMask();
figure, imshow(maskImage);
figure, imshow(Z);
Now, if you didn't do any change to the vertex and just double clicked inside the square you can notice that "maskImage" and "Z" are not the same!
Any one can tell me why is that? and how can we solve it?
Any help will be appreciated.
Meshoo

Accepted Answer

Steve Eddins
Steve Eddins on 27 Mar 2014
Here is some code illustrating how to use bwboundaries to get X-Y polygon vertices that work better for mask creation via createMask or poly2mask (which createMask calls). The idea is to get a polygon that includes the centers of the desired mask pixels inside the polygon instead of along its edges. First, here is your code with some graphics to show the area of each pixel and to show the output of bwboundaries going through pixel centers.
BW = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];
B = bwboundaries(BW);
b = B{1};
imshow(BW,'InitialMagnification','fit');
hold on
[M,N] = size(BW);
x = [0.5 (N+0.5)];
for k = 1.5:(M-0.5)
y = [k k];
plot(x,y,'Color',[.7 .7 .7],'LineStyle','--');
end
y = [0.5 (M+0.5)];
for k = 1.5:(N-0.5)
x = [k k];
plot(x,y,'Color',[.7 .7 .7],'LineStyle','--');
end
plot(b(:,2),b(:,1),'r')
hold off
And here is modified code that produces X-Y values that do not go directly through pixel centers.
BW3 = imresize(Z,3,'nearest');
B3 = bwboundaries(BW3);
b3 = B3{1};
b3 = (b3 + 1)/3;
imshow(BW,'InitialMagnification','fit');
hold on
[M,N] = size(BW);
x = [0.5 (N+0.5)];
for k = 1.5:(M-0.5)
y = [k k];
plot(x,y,'Color',[.7 .7 .7],'LineStyle','--');
end
y = [0.5 (M+0.5)];
for k = 1.5:(N-0.5)
x = [k k];
plot(x,y,'Color',[.7 .7 .7],'LineStyle','--');
end
plot(b3(:,2),b3(:,1),'r')
hold off

More Answers (1)

Steve Eddins
Steve Eddins on 25 Mar 2014
If you are clicking on the centers of the border pixels, then half of the border pixels lie inside the polygonal region you selected and half lie outside. You should click between adjacent pixels instead.
  4 Comments
Steve Eddins
Steve Eddins on 27 Mar 2014
I believe I did understand the question. I'm sorry that my answer cryptic. The X-Y coordinates that are being passed to impoly enclose a region that includes only half of most the pixels around the border of your mask, and only a quarter of the pixels on the corners. The mask "shift" you are observing is simply a consequence of the tie-breaking rules for determining the output value for a pixel that's half inside and half outside the polygon.
The createMask function for impoly and its cousins uses the Image Processing Toolbox poly2mask, and poly2mask has been designed to have a consistent geometry for pixels that have unit area, as opposed to pixels that are defined a zero-area point. Because the output from bwboundaries traces through pixel centers instead of along pixel edges, it doesn't play nicely with the poly2mask geometric conventions.
For than you probably want to know about poly2mask, see these blog postings:
To get output from bwboundaries that works consistently with poly2mask, try the following:
Upsample the binary by a factor of 3 (imresize(BW,3,'nearest')).
Call bwboundaries
Scale and shift the output of bwboundaries back into the original coordinate system.
I'll experiment with some code to do this.
Meshooo
Meshooo on 28 Mar 2014
Indeed thank you very much Steve for the beautiful explanation and solution. Now it is working very well.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!