Calculating perimeter/circumfrence of regions in a binary image through a different approach than regionprops(BW, 'perimeter') *UPDATED*

Suppose I have a binary image with many different regions in it. One region in the image may look like this:
Using regionprops and the 'perimeter' property, Matlab would calculate the green marked perimeter, which for this region would be 17.9460.
Now, what I want to calculate is a little bit different. It's basically the length of the lines forming the region (marked red in the image). Or in other words, the number of green marked "pixels" in the following image, although the blue marked pixles would have to be counted twice to get the length of the lines:
So this would get a length of all lines (or count of pixels) of 24.
Is there a way to do this using some build in Matlab functions in the Image Processing Toolbox?
Thanks in advance, Best Regards

5 Comments

Philip: This is a very interesting question. Thanks for the helpful illustrations to show us what you are trying to achieve.
I'm however a little confused by this statement: "It's basically the length of the lines forming the region. Or in other words, the number of green marked "pixels"". Could you please elaborate on what you mean by 'length of lines forming the region'?
What happens at a corner, like in the second image, where a green pixel has a white pixel to it's north, north-east and east? There are two 'edges' this pixel is representing, but it will be counted only once in the scheme you mention. Should this not be counted twice, then?
Hello Amith, thank you very much for your reply.
"The lines forming the region" are the red marked lines in the following image:
Since the lenght of the lines is equal to the amount of pixels, calculating one or the other shouldn't make any difference. At least, that's what I think.
I suppose, that the pixel that you are refering to, is the marked pixel in the following image (please correct me if I'm wrong):
Since I'm just trying to get the length of the lines forming the region, I don't think, that this pixel needs to be counted twice.
I hope this makes everything a bit more clear for you.
If you have any more questions, feel free to ask as many as you want. Best Regards
I just realised, that I made a mistake. To get the length of the lines, there actually are pixels that need to be counted twice (these are probably the pixels, that you were refering to, Amith). These are the pixels marked in the following image:
So, this would bring the count of pixels to a total of 24 and not 22
I updated my quesion to fit the new description
Thank you for pointing that out, Amith!
You have to be careful of your definitions. For example in this: [0 1 1 1 0], what is the "length" of the line? Is it 3 or is it 2? You could make an argument for either. If two pixels are on a diagonal, is the length 2 or sqrt(2)?
You are right, and thank you for pointing that out. All of these things should be taken into consideration. I'm fairly new to image processing and image analysis, since I started to work on this stuff in september. Therefore, I am still learning a lot of new things each day. Even though, I'm going to leave my solution as the answer to the problem stated above, because it solves this particular problem, despite the fact, that this is not a very accurate calculation of a perimeter.

Sign in to comment.

 Accepted Answer

I tried out a lot of different approaches in the last days and I finally managed to solve this problem. I did this by using Look-Up-Tables and a selfwritten function, that I pass to the Look-Up-Table. So, I basically did this by counting the 'edges' that a single pixel has (not sure if that makes it clear, but here is an image showing this):
Using the following code, I managed to do exactly what the image is showing:
% create T-Shape:
mtrx = zeros(7,9);
mtrx(2, 2:8) = 1;
mtrx(3:6, 4:6) = 1;
% create LUT
lut = makelut(@checkForPixelEdges, 3);
% apply LUT to matrix
out = bwlookup(mtrx, lut);
% get perimeter
perimeter = sum(out(:));
the variable out is a matrix containing the numbers shown in the image above, all other matrix positions are equal to zero. Therefore the sum(out(:)) returns the total length of the lines forming the region (shown red in the images in the question above), which in this case means perimeter = 24 (pixels).
The function checkForPixelEdges() looks like this:
function num = checkForPixelEdges( nhood )
% checkForPixelEdges:
% This function counts the "edges" surrounding a pixel, by checking the
% pixels 4-Neighbourhood-Connectivity.
% Input-Arguments:
% nhood: Neighbourhood defined by makelut()-function. Either a
% 2-by-2-Neighbourhood or a 3-by-3-Neighbourhood
% Output-Arguments:
% num: Number of "edges" surrounding a Pixel, or the number of
% 4-Connected-Neighbourhood-Pixles that are 0
% Example: 0 0 1 --> In this case num = 2, because there are two zero
% 1 1 1 pixels in the 4-Connected-Neighbourhood of the center pixel
% 0 0 1
% check if pixel in the center is 1 or 0
if(nhood(2,2) == 1) % center pixel = 1
% get sum of 4-Connected-Neighbourhood around center pixel
sum_4_nhood = nhood(1,2) + nhood(2,1) + nhood(3,2) + nhood(2,3);
% 3 Neighbours --> 1 edge
if (sum_4_nhood == 3)
num = 1;
% 2 Neighbours --> 2 edges
elseif (sum_4_nhood == 2)
num = 2;
% 1 Neighbour --> 3 edges
elseif (sum_4_nhood == 1)
num = 3;
% isolated pixel with no neighbours (8-Connected-Neighbourhood)
% --> 4 edges
elseif((sum(nhood(:))-nhood(2,2)) == 0)
num = 4;
else % 4 Neighbours --> 0 edges
num = 0;
end
else % center pixel = 0
num = 0;
end
end
This code even works for any arbitrary shape! (as long as the shape doesn't have any holes)
I really want to thank both of you ( Image Analyst and Amith) for commenting on this question and providing some solutions that brought me to my solution!
I'm going to mark my answer as the definitve answer, since it solves the whole problem.

1 Comment

I know this thread is over 3 years old, but this code helped me. Thank you for posting it! I noticed it hasn't been posted on the FileExchange, which is a shame. I would like to put a modified version of this code there via my personal github with a permissive license (UNLICENSE). I will credit you and the other contributors in this thread appropriately, of course. Would that be acceptable to you?

Sign in to comment.

More Answers (1)

Try calling imdilate() followed by bwboundaries() or regionprops(). Let me know what you find out.

1 Comment

Thank you for your reply, dear Image Analyst. I'm currently testing different approaches to achieve my goal, including your suggestion. From the looks of it, your suggestion looks quite promising. I'll let you know what the results are, as soon as I can!

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!