MATLAB: How to distinguish touching and merging shapes on a binary image

image analysisimage processing

I need to detect quasi-round or quasi-elliptical shapes on binary images, see attached image.
To do that I am using "bwlabel":
[labeledImage, numberOfRegions] = bwlabel(binaryImage);
It works well if shapes are isolated from each other. But as soon as they touch or partially merge, they are detected already as one shape. Is there any possibility to distinguish them?
Completely merged in one shape pattern which would be good to treate as one shape looks like that:
Any help is greatly appreciated. Especially in case of partially merged patterns.

Best Answer

Hi Dzmitry-san,
Thank you for sharing your data, and sorry for my late response.
Though I tried the watershed function first, I found that it does not work well (-> it separates the region into 4 segments...). So I tried another method. Here is my try.
I confirmed that this code works well up to 'binaryImage_merged.mat,' but need more trick to address the 'binaryImage_merged_completely.mat.' But anyway, I hope this code would be some help for your research !!
% Read your image
%load('binaryImage_touch.mat');
load('binaryImage_merged.mat');
% Fill the hole
filledBinaryImg = imfill(binaryImage,'holes');
% Calculate surrounding area of 'necks'
CH = bwconvhull(filledBinaryImg);
BW2 = CH & ~filledBinaryImg;
% Delete small regions from the area
se = strel('disk',5);
BW2 = imopen(BW2, se);
BW2 = bwperim(BW2);
% Calculate shortest length between the two regions
labeledBW2 = bwlabel(BW2);
nLabels = max(labeledBW2(:));
distT = array2table(zeros(nLabels*(nLabels-1)/2,7));
distT.Properties.VariableNames =...
{'label1','label2','dist','r1','c1','r2','c2'};
n = 1;
for kk1 = 1:nLabels
[row1,col1] = find(labeledBW2 == kk1);
for kk2 = kk1+1:nLabels;
[row2,col2] = find(labeledBW2 == kk2);
dist = pdist2([row1,col1],[row2,col2]);
[~,idx] = min(dist(:));
[r,c] = ind2sub(size(dist),idx);
distT.label1(n) = kk1;
distT.label2(n) = kk2;
distT.dist(n) = dist(idx);
distT{n,{'r1','c1','r2','c2'}} = [row1(r),col1(r),row2(c),col2(c)];
n = n+1;
end
end
distT = sortrows(distT,'dist');
% Cut the region using 2 shortest paths
BWcutter = false(size(binaryImage));
for kk = 1:2
[cx,cy,~] = improfile(BWcutter,...
distT{kk,{'r1','r2'}},...
distT{kk,{'c1','c2'}});
idx = sub2ind(size(BWcutter),round(cx),round(cy));
BWcutter(idx) = true;
end
BWcutter = imdilate(BWcutter,strel('disk',2));
filledBinaryImg(BWcutter) = false;
% Show the result
labeledImage = bwlabel(filledBinaryImg);
imshow(label2rgb(labeledImage,'jet','k'))