Counting coins on a greyscale image - using morphological and/or f transforms

I am trying to convert the image into a binary image, using the function form: function C = coins2bw(A) where A is a 2D grayscale image variable and C is a 2D binary image variable. The output image C should show the coins as filled in round disks with no other arifacts or stray foreground pixels(background in black while the coins are white). Using only morphological or fourier transforms.

 Accepted Answer

I = imread('image.png');
I = imadjust(I);
[centers,radii] = imfindcircles(I,[15 75],'ObjectPolarity','dark','Sensitivity',0.85);
BW = false(size(I,1),size(I,2));
[Xgrid,Ygrid] = meshgrid(1:size(BW,2),1:size(BW,1));
for n = 1:size(centers,1)
BW = BW | (hypot(Xgrid-centers(n,1),Ygrid-centers(n,2)) <= radii(n));
end
maskedImage = I;
maskedImage(~BW) = 0;
imshow(BW)
fprintf('Numbers of coins: %d\n',size(centers,1))

8 Comments

this script does not use morphological commands, thats as far as I've gotten in class so I need to practice using morphology
function C = coins2bw(A);
A = imread('coins7.png');
[rows, columns, numberOfColorChannels] = size(A);
A = im2gray(A);
figure;
imshow(A);
[pixelCount, grayLevels] = imhist(A);
figure;
bar(pixelCount);
thresholdValue = 180;
binaryIm = A < thresholdValue;
binaryIm = imfill(binaryIm, 'holes');
figure;
imshow(binaryIm);
end
i need help refining so that I can use multiple coin images. I also have to have them counted in the script and Im not sure how to do that
This worked for me
A = imread('image.png');
% Count coins using morphologic operations
thresholdValue = 180;
B = A < thresholdValue;
B = imfill(B, 'holes');
B = bwmorph(B,'branchpoints',16);
B = bwmorph(B,'majority',Inf);
B = bwmorph(B,'shrink',Inf);
numCoins = sum(B>0,'all')
If you put it in a function - like you already have done for the code above, you just need to call the function in a for loop for every single image you have.
I've just noticed that I had to put it in this format:
function coinV = count_coins(A)
where A is a coin image and where coinV is a row vector with the following form
coinV = [Npennies Nnickels Ndimes Nquarters];
could I use size(A) like I did in my first attempt?
Are you allowed to use imfindcircles?
I don't think so, we're exclusively being asked to use grayscale morphology :(
We were given these dimensions also, but no where in our current study section does it mention 'imfindcircles'.
Could you use a 'disk' structuring element?

Sign in to comment.

More Answers (1)

I know you've already accepted an answer and got it solved already, but here's how I'd start:
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
imtool close all; % Close all imtool figures if you have the Image Processing Toolbox.
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;
%===============================================================================
% Read in gray scale image.
folder = pwd;
baseFileName = 'coins.png';
% Get the full filename, with path prepended.
fullFileName = fullfile(folder, baseFileName);
if ~exist(fullFileName, 'file')
% Didn't find it there. Check the search path for it.
fullFileName = baseFileName; % No path this time.
if ~exist(fullFileName, 'file')
% Still didn't find it. Alert user.
errorMessage = sprintf('Error: %s does not exist.', fullFileName);
uiwait(warndlg(errorMessage));
return;
end
end
grayImage = imread(fullFileName);
% Get the dimensions of the image. numberOfColorBands should be = 1.
[rows, columns, numberOfColorBands] = size(grayImage);
% If it's RGB instead of grayscale, convert it to gray scale.
if numberOfColorBands > 1
grayImage = rgb2gray(grayImage);
end
% Display the original image.
subplot(2, 2, 1);
imshow(grayImage);
axis on;
impixelinfo; % Let user mouse around and see gray level.
caption = sprintf('Original Image : %s', baseFileName);
title(caption, 'FontSize', fontSize);
impixelinfo;
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'Outerposition', [0, 0.1, 1, 0.9]);
% Display the histogram
subplot(2, 2, 2);
imhist(grayImage);
grid on;
% Specify a threshold.
threshold = 181
% Place line on histogram at the mean.
xline(threshold, 'Color', 'r', 'LineWidth', 2);
% Create a binary image
mask = grayImage < threshold;
mask = imfill(mask, 'holes');
subplot(2, 2, 3);
imshow(mask);
title('mask', 'FontSize', fontSize);
% Now call imerode to get them to not touch.
% Then call bwlabel to count them.

4 Comments

Is there a way to find circles and estimate the diameters of those circles by using only functions considering the given restrictions?
No. You need something other than only morphological functions like imclose(), imerode(), imdilate(), bwareaopen(), etc. None of those would give you the area (count of pixels) or the diameter. You'd need something like regionprops() or at a minimum the sum() function.
how do I call bwlabel? I havent used that before. Does it have something to do with one of my requirements? --------->
%required:
A is a coin image and where coinV is a row vector with the following form:
coinV = [Npennies Nnickels Ndimes Nquarters];
Once you have the binary image mask of just the coins, then you do
[labeledImage, numRegions] = bwlabel(mask);
% Then if you want to find all the areas and centroids:
props = regionprops(labeledImage, 'Area', 'Centroid');
allAreas = [props.Area]
xy = vertcat(props.Centroid); % List of centroids' (x, y) coordinates.
See my Image Segmentation Tutorial if you want a well commented tutorial:

Sign in to comment.

Asked:

on 10 Nov 2020

Commented:

on 20 Nov 2020

Community Treasure Hunt

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

Start Hunting!