extracting boundaries properties from regionprops()
39 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Elad
el 30 de Jun. de 2023
Comentada: Guillaume
el 7 de Ag. de 2023
Hi all,
Does anyone knows why it can't output a field of "boundary", the same way the function bwboundaries does? Why do I need to use both functions if regionprops already calculate it?
In addiotion, how can I be sure that bothe functions detect the same regions?
Specifically, I want to extract the boundaries of the three dotted spheres in the attached image.
Thank you.
0 comentarios
Respuesta aceptada
Image Analyst
el 12 de Jul. de 2023
If they are known to be spheres, and you want to ignore having a "bay" if there happens to be a black spot on the boundary, you can call bwconvhull and then bwboundaries
% Plot the borders of all the blobs in the overlay above the original grayscale image
% using the coordinates returned by bwboundaries().
% bwboundaries() returns a cell array, where each cell contains the row/column coordinates for an object in the image.
imshow(originalImage); % Optional : show the original image again. Or you can leave the binary image showing if you want.
% Get convex hull of the object
mask = bwconvhull(mask);
% Here is where we actually get the boundaries for each blob.
boundaries = bwboundaries(mask);
% boundaries is a cell array - one cell for each blob.
% In each cell is an N-by-2 list of coordinates in a (row, column) format. Note: NOT (x,y).
% Column 1 is rows, or y. Column 2 is columns, or x.
numberOfBoundaries = size(boundaries, 1); % Count the boundaries so we can use it in our for loop
% Here is where we actually plot the boundaries of each blob in the overlay.
hold on; % Don't let boundaries blow away the displayed image.
for k = 1 : numberOfBoundaries
thisBoundary = boundaries{k}; % Get boundary for this specific blob.
x = thisBoundary(:,2); % Column 2 is the columns, which is x.
y = thisBoundary(:,1); % Column 1 is the rows, which is y.
plot(x, y, 'r-', 'LineWidth', 2); % Plot boundary in red.
end
hold off;
caption = sprintf('%d Outlines, from bwboundaries()', numberOfBoundaries);
fontSize = 15;
title(caption, 'FontSize', fontSize);
axis('on', 'image'); % Make sure image is not artificially stretched because of screen's aspect ratio.
3 comentarios
Image Analyst
el 13 de Jul. de 2023
Then let me answer each one individually:
"Does anyone knows why it can't output a field of "boundary", the same way the function bwboundaries does?" It could but regionprops just doesn't provide a list of (x,y) coordinates of the boundaries. A lot of functions could do additional things but if they're already done by some other function, then they tend not to "double up" on that functionality and provide it in addition to the other function.
"Why do I need to use both functions if regionprops already calculate it?" Well since regionprops doesn't calculate it, the question is moot and you'll have to use bwboundaries.
"In addiotion, how can I be sure that bothe functions detect the same regions?" Both functions can't give you the boundaries. I don't see anywhere in the properties you can ask regionprops for where it says it can return an (x,y) list of perimeter/boundary coordinates. However both functions will operate on all the blobs that are present in the mask image, providing whatever measurements they provide or you ask for.
Más respuestas (2)
Rahul
el 12 de Jul. de 2023
Hi Elad,
According to you question, the regionprops function detects boundary but does not give it as an output, while bwbboundaries does. I went through the documentation for these functions an found:
The regionprops function in MATLAB is primarily designed to calculate and provide measurements of various properties for each connected component or region within an image. While it can provide useful information about the properties of regions, it does not directly output the boundary coordinates of each region.
On the other hand, the bwboundaries function is specifically designed to extract the boundaries of connected components in a binary image. It returns a cell array, where each cell contains the boundary coordinates for a separate region. This function is useful when you specifically need the boundary information and not just the properties of the regions.
To extract the boundaries of the three dotted spheres in your attached image, you can follow these steps:
- Convert the image to a binary image using appropriate thresholding techniques, such as Otsu's method or adaptive thresholding, depending on the characteristics of your image.
- Use the bwboundaries function on the binary image to extract the boundaries of all regions.
- Iterate through the obtained boundaries and filter out the boundaries that correspond to the three dotted spheres based on their size, shape, or any other specific criteria.
- You can then use the regionprops function on the binary image to obtain the properties of the filtered regions, if needed.
By comparing the results obtained from regionprops and bwboundaries, you can ensure that both functions detect the same regions by matching the properties of the regions obtained from regionprops with the boundaries extracted using bwboundaries.
Thanks.
0 comentarios
Guillaume
el 4 de Ag. de 2023
Hi, I'm having the same question. Looking at the regionprops.m code, we see that the coordinates of the boundary are computed, from which is derived the convex hull. Why the regionprops function does not allow the user to output the boundary as well ?
In my case, I'm using the properties computed by regionprops to filter some objects. Afterwards, I need to remove filtered regions, re-create a binary image from the pixel index list, then compute the boundaries with bwboundaries, while this could have been done directly... This is way sub-optimal, furthermore, bwboundaries is slower (~*5) than regionprops requesting for the convex hull (it might be less precise but in my case I don't care).
I guess I could compute features I'm interested in manually from bwboundaries coordinates, but that's more or less re-writing regionprops, that already exists (and computes what I want, just does not want to output it!) so that does not make much sense.
4 comentarios
DGM
el 4 de Ag. de 2023
Editada: DGM
el 4 de Ag. de 2023
There are two different things that can be calculated. You can find an unordered set of pixels that describe the edges of a region, or you can find an ordered list of pixels that describe a continuous path around the edges of a region.
At least for the usage that's being described, the function bwperim() calls bwmorph(), which in turn uses bwlookup(). The calculated perimeter of an object (e.g. 'perim8') is nothing more than the set of true pixels which possess <8 8-neighbors.
% This is a perimeter pixel... but this is not
0 0 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
For 'perim4', it's the set of true pixels with <4 4-neighbors.
% This is a perimeter pixel... but this is not
1 0 0 1 1 0
1 1 1 1 1 1
1 1 0 1 1 0
The entire image is simply scanned and individual pixels which meet this criteria are selected. The output is a logical mask, because generating a logical mask is the purpose of these tools, and to describe an unordered set of coordinates in an image grid, it is appropriate and efficient.
Could you get X-Y (or row-column) coordinates from the logical mask returned by bwperim()/bwmorph()? Yes. Converting between indexing methods (logical mask, linear indices, or subscripts) is rudimentary MATLAB stuff. You could use find() to do the conversion. That said, you need to remember how find() works.
The list of coordinates you get from find() are going to be the locations of nonzero values in the mask that are found as the array is scanned columnwise. Correspondingly, they're going to be ordered according to their linear indices in the mask, which is not a comparably useful ordering. This sequence of coordinates forms a discontinuous path which zig-zags across the region -- and through points which are not in the region if the object is not convex.
This is what regionprops() does in that section of code. It uses bwmorph() to generate a mask on the S.Image (the portion of the mask local to an individual blob), it uses find() to convert the local mask to subscripts, and then it uses S.BoundingBox to shift those local coordinates into coordinates within the whole image. It also shifts everything by a half-pixel so that we're talking about pixel centers. It doesn't do anything to order the points, because it doesn't need them to be ordered.
mask = imread('twistyblob.png')>128;
mask = mask.'; % transpose so that ordering behavior is more obvious
% find the ordered boundary pixels using bwboundaries()
boundaries = bwboundaries(mask,4);
boundaries = boundaries{1}; % just get the first one
% display the boundary on top of the mask
figure
imshow(mask); hold on
plot(boundaries(:,2),boundaries(:,1),'linewidth',5)
% find the perimeter pixels using bwperim()
% this is the same as using bwmorph() in this case
pmask0 = bwperim(mask,4); % a logical mask
pmask1 = bwmorph(mask,'perim4');
isequal(pmask0,pmask1) % show that they're the same
[yp,xp] = find(pmask0); % get unordered pixel subscripts
% display the unordered perimeter on top of the mask
figure
imshow(mask); hold on
plot(xp,yp)
Every function calculates things internally that maybe someone could plausibly want to keep. Regionprops() also calculates the image size, the number of blobs, and the connectivity struct for the entire image. Why not make each of those externally accessible? They're not accessible because that's not the purpose of regionprops().
In the end, regionprops() doesn't do what was requested. Whether you want an ordered or unordered list of pixels, there are basic functions which should do what's intended.
FWIW, the docs (mostly the synopsis) for bwmorph() are a bit lacking. I could say the same for the regionprops() synopsis. As to why 'perim4' and 'perim8' aren't documented, that probably has to do with the extra dimensionality and connectivity functionality that bwperim() adds. I imagine they wanted people learning to use the purpose-specific tool instead of needing to switch between tools simply to access additional options.
In the same vein, that might be an answer to what's probably a lingering doubt. Even if regionprops() doesn't need the ordered lists internally, wouldn't it at least be a convenience for it to be able to internally call bwboundaries() and return the pixel lists in the same struct? Something like
S = regionprops(mask,'boundingbox','boundary'); % hypothetical
Look at the configurability of bwboundaries() and consider that none of the property calculations done by regionprops() are configurable. It does a lot of different things, so there's motivation to keep each thing simple.
Ver también
Categorías
Más información sobre Image Segmentation and Analysis en Help Center y File Exchange.
Productos
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!