Most efficient way to separate numerically labeled objects that share borders?
21 views (last 30 days)
Show older comments
Consider the following image mask:
IM = [0 0 0 1 1 1 1
0 0 1 1 1 1 1
0 2 2 2 1 1 1
2 2 2 2 2 1 0
2 2 2 2 2 0 0];
Objects 1 and 2 share a diagonal border. If I converted this image as shown above into a logical and passed it to regionprops, it would detect only 1 (merged) object, not 2.
I'm looking for the most computationally efficient way to separate these objects. The end result would look something like this:
want = [0 0 0 1 1 1 1
0 0 0 0 1 1 1
0 2 2 0 0 1 1
2 2 2 2 0 0 0
2 2 2 2 2 0 0];
...where regionprops(logical(want)) would result in 2 objects being detected.
The reason I'm asking is that my actual masks are 25000 x 25000 in size, with about 100,000 objects in each. Separating them would be more efficient in terms of both storage and downstream processing. Also, I'm aware that separating these objects will erode them a bit, and a secondary goal is to minimize the amount of erosion and preserve their overall structures, as some of the actual objects can be as little as 10 pixels wide (they are narrow cells).
So far I've thought of some ways to do this, including brute-forcing it by systematically checking each pixel and converting it to a 0 if one of its neighbors is anything other than a 0 or itself, e.g:
IM2 = padarray(IM, [1 1], 0, 'both'); % make some space
for i = 2:size(IM2, 1)-1
for j = 2:size(IM2, 2)-1
% get that pixel and its neighbors
w = IM2(i-1:i+1, j-1:j+1);
% if bordering another object, turn it to 0
if any(~ismember(w(:), [0 IM2(i, j)]))
IM2(i, j) = 0;
end
end
end
out = IM2(2:end-1, 2:end-1); % remove padding
While this method technically works, it's time-consuming for a large image (about 6 hours per 25000 x 25000) and I have quite a few of these images...
I've also tried various other methods, including isolating individual objects, doing morphological erosion on each, and then mapping the results back on the original image, but this is turned out to be far worse than the brute-force method in terms of both computation time and structural preservation.
Does anyone here have experience with efficiently separating these kinds of objects, which are numerically labeled and could be adjacent to each other, such that they can be converted and stored as logical images without losing too much of their morphological properties?
Answers (2)
Image Analyst
on 10 Apr 2023
You don't need bwlabel, like KSSV suggested, because your matrix is already labeled. You can simply use
oneBlob = ismember(IM, numberYouWant);
I don't see why bwperim() would not preserve small objects. I guess I'd need to see an example of that to prove it, like
mask = false(4,4);
mask(2, 2:3) = true
perims = bwperim(mask) % See? All preserved
8 Comments
Image Analyst
on 11 Apr 2023
Like I said, if you cast your labeled matrix to logical, then all your labeled blobs coalesce into one giant blob and regionprops will only give you measurements on the giant blob, not individual blobs.
I really don't know why you think you need to split apart the blobs to call regionprops rather than just put in IM directly and get the measurements for all the blobs at once. Not really sure what you want to measure but if you want the area and perimeter, for all hundred or so blobs, you can simply do this:
props = regionprops(IM, 'table', 'Area', 'Perimeter')
No need to split them apart and measure each one at a time.
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!