How to count number of blobs

38 ビュー (過去 30 日間)
Nguyen Nguyen
Nguyen Nguyen 2023 年 3 月 28 日
回答済み: Image Analyst 2023 年 3 月 30 日
I want to be able to load an image of dice and be able to count how many dots there are. My approach is to use blob detection. My code is below:
clear all
close all
%% Part 1: Getting an Image into Matlab
sf = imread('allDice.jpg');
gs = rgb2gray(sf);
%% Part 2: Image Gradients
[Gx,Gy] = imgradientxy(gs);
mag = sqrt(x.^2+2.*x.*y+y.^2);
magn = uint8(mag);
%% Part 3: Use a LoG Filter to Find Blobs
H = fspecial('log',95,0.5);
logr = imfilter(gs,H);
[centers1, radii1, metric] = ...
[centers2, radii2, metric] = ...
[centers3, radii3, metric] = ...
[centers4, radii4, metric] = ...
centers =[centers1,centers2,centers3,centers4];
centersStrong = centers(1:23,:);
radiiStrong = radii(1:23);
So now that I have detected the blobs, also if you know how to improve this code so that I can detect the blobs better, that'd be greatly appreciated. I don't know how to count the number of blobs in the picture. I know numel and such but I don't know how to apply it to this code.
Thank you!

回答 (2 件)

Image Analyst
Image Analyst 2023 年 3 月 28 日
編集済み: Image Analyst 2023 年 3 月 28 日
I don't know why all novices think that just because you can see edges in the image, that edge detection is automatically the first thing you do. It almost never is.
In your case you can simply just threshold for black pixels. Then call imfill() to get a mask of the six dice shapes. Then use ismember to get a mask for just one dice and then use it to count the number of dots inside. You will have to use imclearborder() to get rid of the black square outline.
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.
Pretty easy but if you really can't figure it out, let me know.
  1 件のコメント
Nguyen Nguyen
Nguyen Nguyen 2023 年 3 月 29 日
Thank you for your response. I've been trying to apply your work to my code. So this is what I have so far:
%% Part 1: Getting an Image into Matlab
fullFileName = 'allDice.jpg';
% If we get here, we should have found the image file.
originalImage = imread(fullFileName);
originalImage = rgb2gray(originalImage);
% Display the grayscale image.
% Method #2: using a logical operation.
thresholdValue = 100;
binary = originalImage < thresholdValue; % Use < if you want to find dark objects instead of bright objects.
binaryImage = imclearborder(binary);
title('Binary Image, obtained by thresholding');
% Identify individual blobs by seeing which pixels are connected to each other. This is called "Connected Components Labeling".
% Each group of connected pixels will be given a label, a number, to identify it and distinguish it from the other blobs.
% Do connected components labeling with either bwlabel() or bwconncomp().
[labeledImage, numberOfBlobs] = bwlabel(binaryImage, 8); % Label each blob so we can make measurements of it
% labeledImage is an integer-valued image where all pixels in the blobs have values of 1, or 2, or 3, or ... etc.
imshow(labeledImage, []); % Show the gray scale image.
title('Labeled Image, from bwlabel()');
% Get all the blob properties.
props = regionprops(labeledImage, originalImage, 'all');
numberOfBlobs = numel(props) % Will be the same as we got earlier from bwlabel().
The imclearborder didn't work, the borders are still there and that's why I couldn't use imfill because all the dots (blobs) on my dice would have gotten erased. When I identified the blobs and counted them I got 27, which wasn't right. Can you help me with this?
Thank you!


Image Analyst
Image Analyst 2023 年 3 月 30 日
OK, maybe my last answer was too advanced for you. Here is a simpler way. Just threshold, get rid of the background, and get the Euler number of each blob.
Euler number = Number of objects in the region (which = 1) minus the number of holes in those objects. So the number of spots is 1- EulerNumber. Here is the full demo:
% Demo by Image Analyst
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 16;
markerSize = 40;
folder = [];
baseFileName = 'allDice.jpg';
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);
grayImage = imread(fullFileName);
% Get the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
if numberOfColorChannels > 1
% It's not really gray scale like we expected - it's color.
fprintf('It is not really gray scale like we expected - it is color\n');
% Extract the blue channel.
grayImage = grayImage(:, :, 3);
% Display the image.
subplot(1, 2, 1);
imshow(grayImage, []);
axis('on', 'image');
title('Original Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Update the dimensions of the image.
% numberOfColorChannels should be = 1 for a gray scale image, and 3 for an RGB color image.
[rows, columns, numberOfColorChannels] = size(grayImage)
% Maximize window.
g = gcf;
g.WindowState = 'maximized';
% Get mask by thresholding at 100.
mask = grayImage > 100;
% Get rid of the white surround.
mask = imclearborder(mask);
% Get rid of any possible remaining noise specks less than 5000 pixels.
mask = bwareaopen(mask, 5000);
subplot(1, 2, 2);
axis('on', 'image');
title('Mask Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Get the Euler number of each blob.
% Euler Number = Number of objects in the region (1) minus the number of holes in those objects.
% So # of holes = 1 - EulerNumber.
props = regionprops(mask, 'EulerNumber', 'Centroid', 'Area')
allAreas = [props.Area]
% Loop through saying how many spots are in each blob.
for k = 1 : numel(props)
numSpots = 1 - props(k).EulerNumber;
x = props(k).Centroid(1);
y = props(k).Centroid(2);
str = sprintf('%d spots', numSpots);
text(x, y, str, 'FontSize', 25, 'Color', 'r', 'FontWeight', 'bold', ...
'HorizontalAlignment','center', 'VerticalAlignment','middle')
Note that the area of the blob will also tell you the number of spots since each of hte 6 dice above will have a unique area (number of pixels) depending on how many spots it has. Once you have the area in pixels you can use a dictionary to get the number of spots.




Community Treasure Hunt

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

Start Hunting!

Translated by