The region's hole has been filled and I want to find all edge pixels in anti-clockwise direction. At first, my solution is
1、 find all pixel at edge
2、get x-direction between centroid and the pixel.
3、sort it.
How to improve it? Image and code as follows, but when I test code, it found that the concave and bulge make it useless because for at these angles there are possible many points.
function nAngle = create_angle_array(nPosition,centroid)
a = repmat(centroid,[size(nPosition,1),1])
nAngle = mod(angle((nPosition-a)*[1;1j]),2*pi)
end
se = strel('rect',[3,3]);
erodeImage = imerode(binaryImage,se);
erodeImageLeft = binaryImage - erodeImage;
% countPixel = sum(erodeImageLeft(:)== true);
[edgeRow_a,edgeCol_a] = find(erodeImageLeft);
if isscalar(edgeRow_a)
edgeRow = [edgeRow_a];
else
edgeRow = edgeRow_a;
end
if isscalar(edgeCol_a)
edgeCol = [edgeCol_a];
else
edgeCol = edgeCol_a;
end
disp(edgeRow);
disp(edgeCol);
angleValue = create_angle_array(cat(2,edgeRow,edgeCol),centroid);
disp(angleValue);
nPixel = cat(2,angleValue,edgeRow,edgeCol);
fprintf('size(nPixelA) is [%s]\n', int2str(size(nPixel)));
disp(nPixel)
nEdgePixel = sortrows(nPixel)
CodePudding user response:
As you've seen, sorting the pixels along an axis does not guarantee a consistent ordering. A more reliable way is to take a pixel and find the next pixel adjacent to it in the proper direction.
To do this, we need to search the adjacent pixels in the proper order. For a counter-clockwise ordering, we'll define the directions as:
1 0 7
\ | /
\|/
2-- --6
/|\
/ | \
3 4 5
For the current pixel, we will start searching for the next pixel in the direction of the previous pixel plus 1 (modulo 8). So if the previous pixel was in direction 6, we'll first look in direction 7, then 0, then 1, until we find the next perimeter pixel. Then repeat until we reach the starting pixel again.
When we select the starting pixel, we don't have a "previous" pixel, so the easiest way to ensure that we don't miss any pixels is to start on one of the extremes (say, leftmost). Then set the direction of the "previous" pixel to the direction you know there are no more pixels, that is, to the left or direction 2. So,
- Set
current_pixel
and assignprevious_direction
as above. Addcurrent_pixel
toperimeter_list
. - Repeat:
- Starting at
previous_direction 1
(modulo 8), search adjacent pixels in order until you find another perimeter pixel. - If the new pixel is equal to the starting pixel,
break
. - Add new perimeter pixel to list. If the direction the new pixel was found in is d, set
previous_direction
tod 4 mod 8
. Set thecurrent_pixel
to the newly-found pixel.
This will find all of the perimeter pixels of a region in the proper order without having to explicitly find the perimeter pixels first. Any "spikes", or one pixel wide lines, protruding from the region will list the pixels twice, once traversing the line in each direction, so your final list might be longer than the number of perimeter pixels. You can also skip filling the holes, unless you need them filled for a future step.
Some things to look out for are making sure that you don't look outside the bounds of the image, and getting MATLAB's 1-based array indexing to work with mod
. Personally, I have a mod1
function to do one-based modulo. If you do this, just change the direction numbers to be 1 to 8 instead of 0 to 7. I chose to start with the leftmost pixel because that's what find(bwimg, 1)
is going to return.