extracting the count and size of white dots as a function of its location

I have drawn a box in one area of my image and a box on the other location of my image, region A and region B. You can observe that the white dots number and size are different in each box. To confirm this, I have divided my image into 12 equally seperate segments across the image. i want to know what is the number and size of the white dots across the image as a function of their segment location? And possibly display a trend of the size and number of white dots in a graph?How would I do this please? Thank you

 Risposta accettata

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.
You can use the Color Thresholder app on the Apps tab of the tool ribbon to get a mask for the white blobs. Export the function then call it in your code. If you can't figure it out, then attach your original, unannotated image.
If you can't figure it out, then tell me how each of the 12 regions are defined/located.

9 Commenti

@Image Analyst Thank you for the demo I will use it to practice but I dont think I quite got it yet.
Image attached, the 12 regions are just equally spaced regions that go across the image. so at the edge of the image is distance 0 then region 1 is just 1/12th of the image and region 2 is 2/12th of the image and so forth.
012/12
Neo, I feel like you're not quite trying hard enough. I told you to use the Color Thresholder and regionprops. And I gave you code earlier to divide the image up into vertical strips.
Anyway, I used the Color Thresholder and regionprops and got the attached program. It gives the following results:
props =
1625×2 table
Area EquivDiameter
____ ________________
32 6.38307648642292
37 6.8636625175777
81 10.1554125038596
30 6.18038723237103
4 2.25675833419103
: :
24 5.52790639154137
123 12.5143303457446
30 6.18038723237103
5 2.52313252202016
4 2.25675833419103
Display all 1625 rows.
You get a table of the areas and equivalent circular diameters of 1625 blobs.
The code is for the entire image. What you have to do is crop your image to the appropriate 1/12th of the original full image, and process that.
i am trying, i promise. i just use yours as positive control.
I am troubleshooting combining the pieces to make something that will work shortly because my first attempt was not correct.
My attempt was not as expected:
% Get the mean of the green pixels
%meanGreen = mean(grayImage(mask))
% Get mean across 12 vertical bands of the image
startingColumns = round(linspace(1, columns+1, 13))
endingColumns = startingColumns(2:end) - 1
for k = 1 : length(endingColumns)
col1 = startingColumns(k);
col2 = endingColumns(k);
% Make a strip
mask = false(size(masksinusoid));
mask(:, col1:col2) = true;
subplot(1, 3, 2);
imshow(mask);
impixelinfo;
axis('on', 'image');
caption = sprintf('Bin #%d', k);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
% Crop the mask image so we get the mask only in the strip zone.
stripMaskImage = masksinusoid(:, col1 : col2);
subplot(1, 3, 3);
imshow(stripMaskImage);
impixelinfo;
axis('on', 'image');
caption = sprintf('Mask in Subimage strip #%d', k);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
% Make measurements of mean graylevel.
%meanGL(k) = mean(grayImage(masksinusoid));
% Count pixels.
areaOfGreenSpots(k) = nnz(stripMaskImage);
% Count number of contiguous regions.
[~, numberOfGreenSpots(k)] = bwlabel(stripMaskImage);
% Measure the size of the spots
% MAIN PART IS RIGHT HERE!!!
% Get all the blob properties.
props = regionprops(labeledImage, originalImage, 'all');
numberOfBlobs = numel(props); % Will be the same as we got earlier from bwlabel().
% Print out the measurements to the command window, and display blob numbers on the image.
textFontSize = 14; % Used to control size of "blob number" labels put atop the image.
% Print header line in the command window.
fprintf(1,'Blob # Mean Intensity Area Perimeter Centroid Diameter\n');
% Extract all the mean diameters into an array.
% The "diameter" is the "Equivalent Circular Diameter", which is the diameter of a circle with the same number of pixels as the blob.
% Enclosing in brackets is a nice trick to concatenate all the values from all the structure fields (every structure in the props structure array).
blobECD = [props.EquivDiameter];
% Loop over all blobs printing their measurements to the command window.
end
for k = 1 : numberOfBlobs % Loop through all blobs.
% Find the individual measurements of each blob. They are field of each structure in the props strucutre array.
% You could use the bracket trick (like with blobECD above) OR you can get the value from the field of this particular structure.
% I'm showing you both ways and you can use the way you like best.
meanGL = props(k).MeanIntensity; % Get average intensity.
blobArea = props(k).Area; % Get area.
blobPerimeter = props(k).Perimeter; % Get perimeter.
blobCentroid = props(k).Centroid; % Get centroid one at a time
% Now do the printing of this blob's measurements to the command window.
fprintf(1,'#%2d %17.1f %11.1f %8.1f %8.1f %8.1f % 8.1f\n', k, meanGL, blobArea, blobPerimeter, blobCentroid, blobECD(k));
% Put the "blob number" labels on the grayscale image that is showing the red boundaries on it.
text(blobCentroid(1), blobCentroid(2), num2str(k), 'FontSize', textFontSize, 'FontWeight', 'Bold', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'middle');
end
figure
subplot(1, 2, 1);
bar(blobECD);
grid on;
title('Count of Green size per Strip Region')
xlabel('Region #')
ylabel('Size #')
OK, try this. I put the code into a loop over the 12 regions for you.
% Demo by Image Analyst
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 16;
%===============================================================================
% Get the name of the image the user wants to use.
baseFileName = 'neo.jpeg';
folder = pwd;
fullFileName = fullfile(folder, baseFileName);
% Check if file exists.
if ~exist(fullFileName, 'file')
% The file doesn't exist -- didn't find it there in that folder.
% Check the entire search path (other folders) for the file by stripping off the folder.
fullFileNameOnSearchPath = baseFileName; % No path this time.
if ~exist(fullFileNameOnSearchPath, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist in the search path folders.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
%=======================================================================================
% Read in image.
rgbImage = imread(fullFileName);
% Get the dimensions of the image.
[rows, columns, numberOfColorChannels] = size(rgbImage)
% Display image.
subplot(1, 3, 1);
imshow(rgbImage, []);
impixelinfo;
axis on;
caption = sprintf('Original RGB Image\n%s', baseFileName);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
% Set up figure properties:
% Enlarge figure to full screen.
g = gcf;
g.WindowState = "maximized";
% Get rid of tool bar and pulldown menus that are along top of figure.
% set(gcf, 'Toolbar', 'none', 'Menu', 'none');
% Give a name to the title bar.
set(gcf, 'Name', 'Demo by ImageAnalyst', 'NumberTitle', 'Off')
drawnow;
%--------------------------------------------------------------------------------------------------
% Get the white parts of the image
[fullMask, maskedRGBImage] = createMask(rgbImage);
fullMask = ~fullMask; % Invert mask
% Display image.
subplot(1, 3, 2);
imshow(fullMask, []);
impixelinfo;
axis on;
title('White Blobs', 'FontSize', fontSize, 'Interpreter', 'None');
hp = impixelinfo(); % Set up status line to see values when you mouse over the image.
drawnow;
% Get mean across 12 vertical bands of the image
startingColumns = round(linspace(1, columns+1, 13))
endingColumns = startingColumns(2:end) - 1
for k = 1 : length(endingColumns)
col1 = startingColumns(k);
col2 = endingColumns(k);
% Put a line on the mask image where this region ends.
subplot(1, 3, 2);
xline(col2, 'Color', 'r', 'LineWidth', 2);
% Crop the mask image so we get the mask only in the strip zone.
stripMaskImage = fullMask(:, col1 : col2);
% Display the strip mask image.
subplot(1, 3, 3);
imshow(stripMaskImage);
impixelinfo;
axis('on', 'image');
caption = sprintf('Mask in Subimage strip #%d', k);
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
drawnow;
% Make measurements of mean graylevel.
%meanGL(k) = mean(grayImage(masksinusoid));
% Count pixels.
areaOfWhiteSpots(k) = nnz(stripMaskImage);
% Count number of contiguous regions.
[~, numberOfBlobs(k)] = bwlabel(stripMaskImage);
% Measure the size of the spots
% Get the number, size, and area of each white blob.
props = regionprops('table', stripMaskImage, 'Area', 'EquivDiameter')
% Print out the measurements to the command window, and display blob numbers on the image.
textFontSize = 14; % Used to control size of "blob number" labels put atop the image.
% Extract all the mean diameters into an array.
% The "diameter" is the "Equivalent Circular Diameter", which is the diameter of a circle with the same number of pixels as the blob.
% Enclosing in brackets is a nice trick to concatenate all the values from all the structure fields (every structure in the props structure array).
allAreas = [props.Area];
allDiameters = [props.EquivDiameter];
% Get the means for this strip.
meanArea(k) = mean([props.Area]); % Get average intensity.
meanDiameter(k) = mean([props.EquivDiameter]); % Get average intensity.
blobCounts(k) = numel(props);
end
%--------------------------------------------------------------------------------------------------
% Plot bar charts of all the measurements.
figure % Open a new figure.
% Plot count of blobs in the strips.
subplot(2, 2, 1);
bar(blobCounts);
grid on;
title('Count of Blobs per Strip Region')
xlabel('Region #')
ylabel('Blob Count')
% Plot mean Area in the strips.
subplot(2, 2, 2);
bar(meanArea);
grid on;
title('Total Area per Strip Region')
xlabel('Region #')
ylabel('Area in Pixels')
% Plot mean diameter in the strips.
subplot(2, 2, 3);
bar(meanDiameter);
grid on;
title('Mean Diameter per Strip Region')
xlabel('Region #')
ylabel('Mean Diameter in Pixels')
%--------------------------------------------------------------------------------------------------
% Label each blob with 8-connectivity, so we can make measurements of it
[labeledImage, numberOfBlobs] = bwlabel(fullMask, 8);
% Apply a variety of pseudo-colors to the regions.
coloredLabelsImage = label2rgb (labeledImage, 'hsv', 'k', 'shuffle');
% Display the pseudo-colored image.
subplot(2, 2, 4);
imshow(coloredLabelsImage);
axis on;
title('Individual Blobs, pseudocolored', 'FontSize', fontSize, 'Interpreter', 'None');
% END OF MAIN SCRIPT
%======================================================================================================================
function [BW,maskedRGBImage] = createMask(RGB)
%createMask Threshold RGB image using auto-generated code from colorThresholder app.
% [BW,MASKEDRGBIMAGE] = createMask(RGB) thresholds image RGB using
% auto-generated code from the colorThresholder app. The colorspace and
% range for each channel of the colorspace were set within the app. The
% segmentation mask is returned in BW, and a composite of the mask and
% original RGB images is returned in maskedRGBImage.
% Auto-generated by colorThresholder app on 05-Feb-2023
%--------------------------------------------------------------------------------------------------
% Convert RGB image to chosen color space
I = rgb2hsv(RGB);
% Define thresholds for channel 1 based on histogram settings
channel1Min = 0.715;
channel1Max = 0.940;
% Define thresholds for channel 2 based on histogram settings
channel2Min = 0.174;
channel2Max = 1.000;
% Define thresholds for channel 3 based on histogram settings
channel3Min = 0.000;
channel3Max = 1.000;
% Create mask based on chosen histogram thresholds
sliderBW = (I(:,:,1) >= channel1Min ) & (I(:,:,1) <= channel1Max) & ...
(I(:,:,2) >= channel2Min ) & (I(:,:,2) <= channel2Max) & ...
(I(:,:,3) >= channel3Min ) & (I(:,:,3) <= channel3Max);
BW = sliderBW;
% Initialize output masked image based on input image.
maskedRGBImage = RGB;
% Set background pixels where BW is false to zero.
maskedRGBImage(repmat(~BW,[1 1 3])) = 0;
end
i'm not sure where I went wrong, can you make suggestion on what I can review so that I can fully understand? Thank you.
There were many problems and I can't go over them all but basically you didn't need two for loops, and in your second one you were overwriting the results on each interation, not using an index to save them into an array. I think there were also problems with knowing which mask to use.
I'm wondering what's the difference between graphing the mean diameter of pixels in the image vs. mean diameter of white spots in the image?
I didn't compute the mean diameter of the pixels. I just computed the mean diameter of the white spots. The "size" of a pixel is the field of view (in microns) divided by the number of pixels across the image. It's just a single number so there is nothing to graph.

Accedi per commentare.

Più risposte (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by