Particle size distribution using image processing in MATLAB
Show older comments

I want to plot the number of fat cells in the liver versus their size. For which I wanted to use the following steps.
- Apply adaptive thresholding on the gray level image.
- Find distance transform on the thresholded image.
- Invert the distance transform and assign a high value to the background.
- Extract marker using gray scale reconstruction and assign zero value to marker.
- Apply watershed transformation on the marker embedded inverted distance image to obtain the segmented image.
- Use gray scale reconstruction to find radius of each droplet and subsequently calculate area of each labelled droplet.
In step 3 how do I assign a high value to the background and can you help me with step 4?
8 Comments
Image Analyst
on 3 Mar 2013
Which color is the fat cells? Why are you doing marker-based watershed? Are you trying to follow Steve's demo: http://blogs.mathworks.com/steve/2006/06/02/cell-segmentation/
amrutha Priya
on 3 Mar 2013
Image Analyst
on 3 Mar 2013
I can't see the article because I don't have an account. Can you show your code so far? Are you able to adapt Steve's algorithm? It shouldn't be too hard.
amrutha Priya
on 3 Mar 2013
Edited: amrutha Priya
on 3 Mar 2013
amrutha Priya
on 3 Mar 2013
amrutha Priya
on 3 Mar 2013
Image Analyst
on 3 Mar 2013
I don't have time to write or debug it for you. But I did download your image and looked at its color channels and noticed that you'll get a lot better contract just using the green channel than using rgb2gray() because the red and blue channels are practically worthless and you don't want them to ruin your gray scale image.
amrutha Priya
on 4 Mar 2013
Accepted Answer
More Answers (3)
khaled soliman
on 10 Jul 2021
0 votes
Dear ImageAnalyst,
I want to determine the particular size of spray droplets which is attached
9 Comments
Image Analyst
on 11 Jul 2021
Sorry - the droplets are not individually resolvable.
Jordan Rayner
on 11 Nov 2021
Hi Image Analyst
Can the particle size, of the particles in focus, be determined?
Image Analyst
on 11 Nov 2021
@khaled soliman, this is not an answer to @amrutha Priya. Please start your own question. ALso search for "spray" since I've answered spray questions several times.
@Jordan Rayner you should try to get a better picture first.
Image Analyst
on 21 Mar 2024
It's a generic, general purpose demo of how to threshold an image to find blobs, and then measure things about the blobs, and extract certain blobs based on their areas or diameters.
Basically get the diameters or areas and take the histogram
props = regionprops(mask, 'Area', 'EquivDiameter');
histArea = histogram([props.Area])
histDiam = histogram([props.EquivDiameter])
Aditya Sai Deepak
on 30 Apr 2024
how can we find the size of the particles for few different images and make a histogram of all the images into one histogram graph stating like we found ---- this many particles around --- this size ??
Image Analyst
on 30 Apr 2024
@Aditya Sai Deepak, see the FAQ for code samples on how to process a sequence of files:
Inside the loop over files, accumulate your data for areas into one variable then pass it to histogram
% Set these to null before your loop begins though to initialize them!!!
allAreas = [];
allDiams = [];
for k = 1 : numberOfFiles
% Insert extra code here, to read in image, create mask, etc.
% Now measure particles.
props = regionprops(mask, 'Area', 'EquivDiameter');
% Display histograms for this one image.
histArea = histogram([props.Area])
histDiam = histogram([props.EquivDiameter])
% Accumulate
allAreas = [allAreas, [props.Area]];
allDiams = [allDiams, [props.EquivDiameter]];
end
Then after the loop display the histograms of the grand totals:
histogram(allAreas);
Aditya Sai Deepak
on 30 Apr 2024
suppose if i have a 500 nm images , how will I get the size of the particales in nm thorugh histogram data .? I am confused in converting this ,
The bin Values in histogram data are the actual sizes of the particle or should we use some formula to convert them into nm ??
Image Analyst
on 1 May 2024
Everything is in pixels. You need to know how many nm per pixel and then multiply the diameter in pixels by the number of nm/pixel.
diameterInNm = diameterInPixels * nmPerPixel; % Pixels cancel out and you're left with units of nm.
See attached demo.
Image Analyst
on 2 May 2024
@Aditya Sai Deepak please start your own discussion thread so we don't keep bugging @amrutha Priya with emails of activity on this thread. Attach your code and a couple of images, zipped up.
There I can help you if changing this
baseFileName = TifFiles(k).name;
to this
baseFileName = theFiles(k).name;
does not work.
Maria Luisa Muñoz Leon
on 23 Apr 2023
0 votes
Hi
Can you give the name of the dataset please ?
2 Comments
Image Analyst
on 23 Apr 2023
What do you mean by dataset? The image that the original poster was using was attached to the original post. Just download it.

DGM
on 23 Apr 2023
Or you can look at the link that's next to the attached image in order to find the source.
Histological patterns in drug-induced liver disease
Witek Jachimczyk
37 minutes ago
Edited: Torsten
1 minute ago
This thread has a good accepted answer for plotting a histogram of droplet sizes from a binary image, but a few parts of the original question were not yet addressed. The script below runs on the liver image attached to the question and fills those gaps. It carries out the steps 3 and 4 that were asked about: after inverting the distance transform it sets the background to Inf, then extracts markers with imextendedmin (an h-minima transform built on imreconstruct) and uses them in a marker-controlled watershed. That separates touching fat droplets that bwlabel alone counts as one object (about 490 droplets instead of 403). It also discards droplets cut off by the image edge, since their true size is unknown and they would make the distribution come out too small. It fits the size distribution instead of only plotting it. The earlier suggestion of a log-normal distribution is implemented with fitdist, and because this image clearly contains two droplet populations (small droplets with a median of about 19 px and large ones with a median of about 39 px), the script also fits a two-component log-normal mixture and compares the two models with BIC. Finally, on the ~1.129 ratio @Valeriy reported: EquivDiameter is the diameter of a circle with the same area, so a square of side s gives 2s/sqrt(pi) = 1.128*s. The ratio comes from the square test particles, not from overlap. Set umPerPixel to your calibration to get sizes in micrometres. The threshold and hMin are the two parameters most worth adjusting for other images.
%% Fat droplet size distribution from a liver histology image
% Marker-controlled watershed separates touching droplets, then the
% equivalent diameters are fitted with a log-normal distribution.
%% Parameters
imageFile = 'temp.jpg'; % image attached to the original question
umPerPixel = 1; % spatial calibration (set to 1 to stay in pixels)
threshold = 205; % green-channel level separating droplets from tissue
minArea = 50; % smallest droplet to keep, in pixels
hMin = 2; % marker depth; raise if over-split, lower if under-split
nBins = 30;
%% 1. Read image and take the green channel (best white-vs-pink contrast)
rgb = imread(imageFile);
g = imgaussfilt(rgb(:,:,2), 1.5);
%% 2. Threshold and clean-up
% Droplets are near-saturated white; Otsu (~171) would include pale tissue
bw = g >= threshold;
bw = imopen(bw, strel('disk', 2));
bw = imfill(bw, 'holes');
bw = bwareaopen(bw, minArea);
%% 3. Inverted distance transform, background set to a high value
D = -bwdist(~bw);
D(~bw) = Inf;
%% 4. Markers by grayscale reconstruction (h-minima) and watershed
markers = imextendedmin(D, hMin);
D2 = imimposemin(D, markers);
L = watershed(D2);
L(~bw) = 0;
%% 5. Discard droplets cut off by the image edge (their size is unknown)
edgeLabels = unique([L(1,:), L(end,:), L(:,1)', L(:,end)']);
L(ismember(L, edgeLabels)) = 0;
%% 6. Measure each droplet
stats = regionprops(L, 'Area', 'EquivDiameter');
stats = stats([stats.Area] >= minArea);
diams = [stats.EquivDiameter]' * umPerPixel;
fprintf('Droplets measured: %d\n', numel(diams));
%% 7. Fit a log-normal distribution
pd = fitdist(diams, 'Lognormal');
fprintf('Log-normal fit: mu = %.3f, sigma = %.3f (median diameter = %.2f)\n', ...
pd.mu, pd.sigma, median(pd));
%% 8. Two-population fit (small + large droplets): log-normal mixture
gm = fitgmdist(log(diams), 2, 'Replicates', 10, 'Options', statset('MaxIter', 1000));
[~, order] = sort(gm.mu);
fprintf('Mixture: median %.2f, sigma %.3f, fraction %.2f\n', [exp(gm.mu(order))'; ...
sqrt(squeeze(gm.Sigma(order)))'; gm.ComponentProportion(order)]);
fprintf('BIC: single log-normal %.1f, mixture %.1f (lower is better)\n', ...
fitgmdist(log(diams), 1).BIC, gm.BIC);
%% 9. Display
if umPerPixel == 1, unitLabel = 'pixels'; else, unitLabel = '\mum'; end
figure('Name', 'Fat droplet sizes', 'Position', [100 100 1100 750]);
subplot(2,2,1); imshow(rgb); title('Image');
subplot(2,2,2); imshow(bw); title('Binary');
subplot(2,2,3); imshow(imoverlay(rgb, boundarymask(L), 'k')); title('Separated droplets');
subplot(2,2,4);
histogram(diams, nBins, 'Normalization', 'pdf'); hold on
x = linspace(0, max(diams), 300);
plot(x, pdf(pd, x), 'r-', 'LineWidth', 2);
x = x(2:end); % mixture pdf in diameter space: f(log d)/d
plot(x, pdf(gm, log(x'))' ./ x, 'k--', 'LineWidth', 2); hold off
xlabel(['Equivalent diameter (' unitLabel ')']); ylabel('Probability density');
legend('Measured', 'Log-normal fit', 'Two-population fit'); title('Size distribution');
Categories
Find more on Data Preprocessing in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!
