Reputation: 1
I have two images with multiple dots on the surface
How can I estimate those dots' density on the image and then, compare them to another image with different dots concentration? I want to know in what image the dots have more density.
I tried to make it with Emgu CV, but did not manage to find any method.
Upvotes: 0
Views: 456
Reputation: 687
We do a similar thing here using OpenCV.
You could first try finding the dots by using a binary threshold on the intensity and thus creating a mask (Cv2.Threshold
).
On the mask you can use Cv2.FindContours
to automatically get a list of point lists that give you the contours of each dot.
You could use that contours positions to check each dot's density.
A contour (= point list) can also be used in methods like e.g. Cv2.ContourArea
, Cv2.ArcLength
, Cv2.BoundingRect
in order to get the dot's geometry properties.
Upvotes: 0
Reputation: 60564
There are multiple approaches to this problem.
Below I use MATLAB with DIPimage to demonstrate the methods. I don't know C#, but OpenCV (and thus EmguCV) has sufficient methods needed to implement #1 and #2, though probably not as easily as it's done with DIPlib.
All demos use pixels as units, if you have the proper pixel size recorded, you should use that to derive distances and densities in physical units.
To detect these dots precisely is not trivial, but to get an estimate of the density we don't need to be very precise, a few misses are fine. The Laplace of Gaussian filter is ideal for this, the number of local maxima in the output corresponds approximately to the number of dots in the image.
img = readim('https://i.sstatic.net/TNj3p.jpg');
img = img{1}; % just one channel, all three are identical
% Approach 1: detect and count
dots = laplace(img, 3); % find the right filter size, depending on the noise in the image
dots = maxima(dots, 2);
overlay(img, dots) % display
density = max(label(dots)) / numel(img) % dots/pixel, use physical dimensions if known.
The density estimated is 0.0065 dots per pixel.
This is likely the most robust method. We apply a Hamming window function to the image to avoid edge effects (any windowing function will do well enough), compute the Discrete Fourier Transform (with the FFT), and take its magnitude. This will show a neat ring whose size is given by the density of dots. Next, we compute the mean value for each radius (distance from the origin), ignore the first few bins (these are dominated by the windowing function), and find the peak.
F = abs(ft(window(img)));
F = radialmean(F);
F(0:3) = 0; % remove frequencies dominated by windowing function
plot(linspace(0, imsize(F)/2, imsize(F)), F) % display
[~,ii] = max(F);
distance = imsize(F) / ii / 2 % in pixels, use physical dimensions if known.
The distance estimated is 5.78 pixels.
The variogram is a statistical tool designed for analyzing spatial dependence. We can use it to determine an average distance between dots.
semi = semivariogram(img);
x = semi(:,1);
y = semi(:,2);
plot(x,y) % display
ii = find(maxima(y),1); % the first local maximum is the one we want
distance = x(ii) % in pixels, use physical dimensions if known.
The semivariogram has a little peak before it sets into the fixed trend (sill). The peak is at 7 pixels in this case. I think the results might be somewhat more robust if we were to apply a small Gaussian smoothing to the semivariogram before looking for the peak.
Upvotes: 1