The "watershed" approach should be able to handle this problem. Even though the "watershed" function splits the edges into separate objects, it should still produce a decent approximation of the drop centroid. I will describe my approach to this problem below. If this is not useful to you, please upload one of your images so I can better understand the situation.
I will start by making a sample image with three overlapping drops:
%make a sample image
N = 100;
im = zeros(N);
xCentroid = [40,60,50];
yCentroid = [40,40,70];
radius = [15,10,20];
theta = linspace(0,2*pi,100);
[X,Y] = meshgrid(1:N);
for ai = 1:length(xCentroid)
im(sqrt((X-xCentroid(ai)).^2+(Y-yCentroid(ai)).^2)<radius(ai)) = 1;
end
The "bwdist" function is used to compute the distance transform of the inverted binary image. The "watershed" function is then used to detect the different drops:
%use watershed analysis
D = -bwdist(~im,'euclidean');
D(~im) = -inf; %set background to be infinitely far away
im2 = watershed(D);
Now, the "regionprops" function is used to detect the centroid, equivalent diameter, and perimeter of each drop:
%get the region properties
props = regionprops(im2,'centroid','equivdiameter','perimeter');
Now, the results are plotted. Note that when plotting the detected centroids, I have included a conditional statement to check if the detected drop is roughly a circle. This is used to automatically ignore other objects that are not drops.
%plot the results
figure;
imagesc(im);
hold on;
%plot the actual centroids
for ai = 1:length(xCentroid)
p(1) = plot(xCentroid(ai),yCentroid(ai),'r+','markersize',10);
end
%loop over all detected objects
for ai = 1:length(props)
%check if it is a circle
if abs(props(ai).Perimeter-pi*props(ai).EquivDiameter)/props(ai).EquivDiameter < 0.1
%plot the detected centroid
p(2) = plot(props(ai).Centroid(1),props(ai).Centroid(2),'kx','markersize',10);
end
end
legend(p,{'Actual centroid','Detected centroid'});
The error associated with each detection is as follows:
Circle 1: xCentroidError = 0.7387%, yCentroidError = 1.1352%, DiameterError = 11.39%
Circle 2: xCentroidError = 0.1190%, yCentroidError = 0.4080%, DiameterError = 7.51%
Circle 3: xCentroidError = 0.9140%, yCentroidError = 0.0000%, DiameterError = 16.89%
This method is very accurate at picking out the centroids but is less accurate in determining the drop diameter. A portion of the diameter error may be due to the single pixel outline removed from each object by the "watershed" function. To mitigate this, you can "thicken" each detected object by one pixel around its edge using the "bwmorph" function. For example, if you want to thicken the second object detected, you can use:
nextdrop = bwmorph(im2==2,'thicken');
Just as a check, you can see that this operation increases the equivalent diameter by about two pixels:
>> regionprops(im2==2,'equivdiameter') %standard
ans =
EquivDiameter: 26.5829
>> regionprops(bwmorph(im2==2,'thicken'),'equivdiameter') %thickened
ans =
EquivDiameter: 28.4790
For your reference, I have included links to some useful documentation pages below: