Valid Coin Mask True Pixels Error Outside or Beyond the Actual Mask Error

imread("testCoinImage3.png");
[testcoinMask,MaskedtestCoin] = segmentCoinFace(testCoinImage);
se = strel("disk", 4, 0);
testcoinMask = imfill(testcoinMask, "holes");
testcoinMask = imerode(testcoinMask, se);
imgFilt = imgaussfilt(MaskedtestCoin, 1, 'Padding', 'circular', 'FilterDomain', 'frequency', 'FilterSize', 3);
faceEdgeMask = edge(imgFilt, "sobel", 0.09, "both");
faceEdgeMask(~testcoinMask) = false;
seFE = strel("disk",75,0);
fEdgeMask = imfill(faceEdgeMask, "holes");
BW2 = imdilate(fEdgeMask,seFE);
validCoinMask = BW2 & testcoinMask;
se2 = strel('disk',75,0);
validcoinMask = imdilate(validCoinMask, se2);
coinProps = regionprops("table", validCoinMask, 'Area', 'Perimeter');
areas = table2array(coinProps(:, 'Area'));
range = [min(areas ) max(areas)];
validCoinMask = bwareafilt(validCoinMask, range);
imshow(validCoinMask)
function [BW,maskedImage] = segmentCoinFace(X)
%segmentImage Segment image using auto-generated code from Image Segmenter app
% [BW,MASKEDIMAGE] = segmentImage(X) segments image X using auto-generated
% code from the Image Segmenter app. The final segmentation is returned in
% BW, and a masked image is returned in MASKEDIMAGE.
% Auto-generated by imageSegmenter app on 08-Jul-2023
%----------------------------------------------------
% Adjust data to span data range.
X = imadjust(X);
% Threshold image with global threshold
BW = imbinarize(im2gray(X));
% Open mask with default
radius = 2;
decomposition = 0;
se = strel('disk', radius, decomposition);
BW = imopen(BW, se);testCoinImage = imread("testCoinImage3.png");
[testcoinMask,MaskedtestCoin] = segmentCoin(testCoinImage);
% Shrink the coin mask.
se = strel('disk', 3, 0);
testcoinMask = imfill(testcoinMask, 'holes'); % Fill any holes in it.
testcoinMask = imerode(testcoinMask, se); % Shrink by 3 layers of pixels.
% Find edges using original poster's code.
imgFilt = imgaussfilt(MaskedtestCoin,0.7,...
Padding="circular",FilterDomain="frequency",FilterSize=3);
faceEdgeMask = edge(imgFilt,"sobel",0.1,"both");
% Erase outside the shrunken coin mask to get rid of outer boundary.
faceEdgeMask(~testcoinMask) = false;
imshow(faceEdgeMask);
function [BW,maskedImage] = segmentCoin(X)
%segmentImage Segment image using auto-generated code from Image Segmenter app
% [BW,MASKEDIMAGE] = segmentImage(X) segments image X using auto-generated
% code from the Image Segmenter app. The final segmentation is returned in
% BW, and a masked image is returned in MASKEDIMAGE.
% Auto-generated by imageSegmenter app on 08-Jul-2023
%----------------------------------------------------
% Adjust data to span data range.
X = imadjust(X);
% Threshold image with global threshold
BW = imbinarize(im2gray(X));
% Open mask with default
radius = 2;
decomposition = 0;
se = strel('disk', radius, decomposition);
BW = imopen(BW, se);
% Close mask with default
radius = 2;
decomposition = 0;
se = strel('disk', radius, decomposition);
BW = imclose(BW, se);
% Fill holes
BW = imfill(BW, 'holes');
% Invert mask
BW = imcomplement(BW);
% Invert mask
BW = imcomplement(BW);
% Create masked image.
maskedImage = X;
maskedImage(~BW) = 0;
end
% Close mask with default
radius = 2;
decomposition = 0;
se = strel('disk', radius, decomposition);
BW = imclose(BW, se);
% Fill holes
BW = imfill(BW, 'holes');
% Invert mask
BW = imcomplement(BW);
% Invert mask
BW = imcomplement(BW);
% Create masked image.
maskedImage = X;
maskedImage(~BW) = 0;
end
in the se variable for structuring element , when I change the value to 4 it shows "Your valid coin mask has one or more true pixels outside valid coins," and when I change the se value to another value later on, it would show that it isn't covering all true valid coins . Please if you can help, I've been stuck on this since the past 3 days and I'm getting quite frustrated grrr. Thanks :)

2 Comments

@Image AnalystHello there sir, if you would be kind enough to check the abive code and tell me whats wrong, becaus eive used this same code in the next/last step of the project to the count the value of the coins and ive passed it.
There is a forum in the course, and I have it on good authority that the course authors are very responsive. Have you tried asking your question there?

Answers (4)

I don't think most of that is needed. I would just threshold, call imfill, and then call bwareaopen. The double imcomplement and imopen stuff are most likely not needed, however I can't run your code until tonight because I'm traveling and on a computer without MATLAB.

13 Comments

testImageIdx = randi([1,3])
testCoinImage = imread("testCoinImage"+testImageIdx+".png");
testCoinImage = imread("testCoinImage3.png");
[testcoinMask, MaskedtestCoin] = segmentCoinFace(testCoinImage);
se = strel("disk", 3, 0);
testcoinMask = imfill(testcoinMask, "holes");
testcoinMask = imerode(testcoinMask, se);
imgFilt = imgaussfilt(MaskedtestCoin, 1, 'Padding', 'circular', 'FilterDomain', 'frequency', 'FilterSize', 3);
faceEdgeMask = edge(imgFilt, "sobel", 0.09, "both");
faceEdgeMask(~testcoinMask) = false;
seFE = strel("octagon", 90);
fEdgeMask = imfill(faceEdgeMask, "holes");
BW2 = imdilate(fEdgeMask, seFE);
validCoinMask = BW2 & testcoinMask;
se2 = strel('octagon', 90);
validcoinMask = imdilate(validCoinMask, se2);
coinProps = regionprops("table", validCoinMask, 'Area', 'Perimeter');
areas = table2array(coinProps(:, 'Area'));
range = [min(areas) max(areas)];
validCoinMask = bwareafilt(validCoinMask, range);
imshow(validCoinMask)
function [BW, maskedImage] = segmentCoinFace(X)
%segmentImage Segment image using auto-generated code from Image Segmenter app
% [BW, MASKEDIMAGE] = segmentImage(X) segments image X using auto-generated
% code from the Image Segmenter app. The final segmentation is returned in
% BW, and a masked image is returned in MASKEDIMAGE.
% Auto-generated by imageSegmenter app on 08-Jul-2023
%----------------------------------------------------
% Adjust data to span data range.
X = imadjust(X);
% Threshold image with global threshold
BW = imbinarize(im2gray(X));
% Open mask with default
radius = 2;
decomposition = 0;
se = strel('disk', radius, decomposition);
BW = imopen(BW, se);
% Fill holes
BW = imfill(BW, 'holes');
% Create masked image.
maskedImage = X;
maskedImage(~BW) = 0;
end
I ran the following more simplified code according to the suggestion you had provided above, however it's still persistant on the same error message as above. "Your valid coin mask has one or more true pixels outside valid coins."
I just ran this code and it throws no such error. However the algorithm is still crazy and bizarre and not robust. Do you want me to fix it?
please fix it for me, i'm also stuck and have tried several times
@Ariba why do you have the same problem and images as @Ahsan? Is this an assignment from a class?
Have you seen my (essentially similar) demo in my Image Segmentation Tutorial in my File Exchange:
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.
nope this is an assignment in an image processing code of coursera
this is code i have written for it now after 70 tries:
testImageIdx = randi([1,3])
testImageIdx = 1
testCoinImage = imread("testCoinImage"+testImageIdx+".png");
Error using imread>get_full_filename
File "testCoinImage31.png" does not exist.

Error in imread (line 372)
fullname = get_full_filename(filename);
imshow(testCoinImage);
[validCoinMask,maskedCoinImage] = segmentCoin(testCoinImage);
imshow(validCoinMask)
imshow(maskedCoinImage)
bw = maskedCoinImage > 100;
imshow(bw)
coinSizes = regionprops("table",bw,"Area","Perimeter");
nDimes = coinSizes.Area < 4100;
nDimes = sum(nDimes);
nNickels = (coinSizes.Area > 4100 & coinSizes.Area <6000);
nNickels = sum(nNickels);
nQuarters = (coinSizes.Area > 6000 & coinSizes.Area < 7800);
nQuarters = sum(nQuarters);
nFiftyCents = coinSizes.Area > 7800;
nFiftyCents = sum(nFiftyCents);
USD = (nDimes * 0.10) + (nNickels * 0.05) + ...
(nQuarters * 0.25) + (nFiftyCents * 0.50)
%%
function [validCoinMask,maskedCoinImage] = segmentCoin(X)
%segmentImage Segment image using auto-generated code from Image Segmenter app
% [BW,MASKEDIMAGE] = segmentImage(X) segments image X using auto-generated
% code from the Image Segmenter app. The final segmentation is returned in
% BW, and a masked image is returned in MASKEDIMAGE.
% Auto-generated by imageSegmenter app on 31-Dec-2022
%----------------------------------------------------
% Threshold image - manual threshold
validCoinMask = im2gray(X) > 188;
% Close mask with default
radius = 15;
decomposition = 0;
se = strel('disk', radius, decomposition);
validCoinMask = imclose(validCoinMask, se);
% Create masked image.
maskedCoinImage = X;
maskedCoinImage(~validCoinMask) = 0;
end
and have updated again:
function [validCoinMask, testCoinMask] = segmentCoinFace(testCoinImage)
% Convert the image to grayscale if it is not already
if size(testCoinImage, 3) > 1
testCoinImage = rgb2gray(testCoinImage);
end
% Manual threshold
threshold = 0.5; % You may need to adjust this value
% Apply threshold to create an initial mask
testCoinMask = testCoinImage > threshold;
% Apply morphological operations
se = strel("disk", 25);
testCoinMask = imfill(testCoinMask, "holes");
testCoinMask = imerode(testCoinMask, se);
% Create masked image and apply Gaussian filter
MaskedtestCoin = testCoinImage;
MaskedtestCoin(~testCoinMask) = 0;
imgFilt = imgaussfilt(MaskedtestCoin, 1, "Padding", "circular", "FilterDomain", "frequency", "FilterSize", 3);
% Detect edges
faceEdgeMask = edge(imgFilt, "sobel", 0.04, "both");
faceEdgeMask(~testCoinMask) = false;
% Apply morphological operations
seFE = strel("disk", 60);
fEdgeMask = imfill(faceEdgeMask, "holes");
BW2 = imdilate(fEdgeMask, seFE);
validCoinMask = BW2 & testCoinMask;
% Apply dilation
se2 = strel('disk', 65);
validCoinMask = imdilate(validCoinMask, se2);
% Filter by area to select the blobs in a certain size range.
minArea = 5; % Define the minimum area of the coins
maxArea = 5000; % Define the maximum area of the coins
validCoinMask = bwareafilt(validCoinMask, [minArea, maxArea]);
% Compute properties of valid coins
coinProps = regionprops("table", validCoinMask, "Area", "Perimeter", "Centroid");
disp(coinProps);%
% Create masked image.
maskedCoinImage = X;
maskedCoinImage(~validCoinMask) = 0;
end
@Image Analyst Hello sir , ive tried several attempts but ive been unsuccesful thus so far, my coursera is going to be deactivated by the end if this month, If you can write the correct code for it and send it to me so that I can see for myself and compare for what i have done wrong and learn from it , thanks.
@Image Analyst yes sir if you can fix the above algrothim it would mean the world to me , regards
the above link is the assignment in coursera for which im trying to work and get my correct solution but failing thus so far, if you can access it and take a look at the above link, try it yourself and see if you can get any correct solutions for it .
@Image Analyst sorry for so many messages but today is the last day for my coursera deadline sir, please if you could send the correct code to the question in the link provided above by me in the previous comment , it would be evreything . I dont want to lose my progress sir of this course that i had put in so much time and effort for sir , thankyou
same, I have to complete it before the deadline anyhow
@Ahsan I threw out most of the unnecessary code and simplified it greatly. Here is what I got:
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 = 18;
testCoinImage = imread("testCoinImage3.png");
subplot(2, 2, 1);
imshow(testCoinImage)
title('Original Image', 'FontSize', fontSize)
% Segment the image.
[coinMask, MaskedtestCoin] = segmentCoinFace(testCoinImage);
subplot(2, 2, 2);
imshow(coinMask)
title('Mask', 'FontSize', fontSize)
subplot(2, 2, 3);
imshow(MaskedtestCoin)
title('Masked Image', 'FontSize', fontSize)
% Measure areas and perimeters.
coinProps = regionprops(coinMask, 'Area', 'Perimeter');
allAreas = [coinProps.Area]
allPerimeters = [coinProps.Perimeter]
range = [min(allAreas) max(allAreas)]
subplot(2, 2, 4);
bar(allAreas);
grid on;
title('Coin Areas', 'FontSize', fontSize)
%===========================================================================
function [BW, maskedImage] = segmentCoinFace(inputImage)
%segmentImage Segment image using auto-generated code from Image Segmenter app
% [BW, MASKEDIMAGE] = segmentImage(X) segments image X using auto-generated
% code from the Image Segmenter app. The final segmentation is returned in
% BW, and a masked image is returned in MASKEDIMAGE.
% Auto-generated by imageSegmenter app on 08-Jul-2023
%----------------------------------------------------
% Threshold image with global threshold
BW = imbinarize(im2gray(inputImage));
% Fill holes
BW = imfill(BW, 'holes');
% Find areas so we know what size blobs to exclude..
% props = regionprops(BW, 'Area');
% allAreas = sort([props.Area])
% Throw out blobs less than 2000 in area.
BW = bwareaopen(BW, 2000);
% Create masked image.
maskedImage = inputImage;
maskedImage(~BW) = 0;
end

5 Comments

it is segmentatiin all the coin, we need to segment valid coins only
What exactly defines a "valid" coin? I thought they all were. Is it the ones that are fairly smooth looking? I thought those were just over exposed. Have you tried computing the standard deviation of the blobs PixelValues?
@Image Analystvalid coins are the ones that have a visible face of a coin, as you can see there are some blank circles along with the valid coins . We have to only segment and mask the face of actual coins and not the blanks
So I guess the answer is "No, I didn't try what you said" about standard deviations.
OK, so here is how you could do it:
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 = 18;
testCoinImage = imread("testCoinImage3.png");
subplot(2, 2, 1);
imshow(testCoinImage)
title('Original Image', 'FontSize', fontSize)
[coinMask, MaskedtestCoin] = segmentCoinFace(testCoinImage);
subplot(2, 2, 2);
imshow(coinMask)
title('Mask', 'FontSize', fontSize)
subplot(2, 2, 3);
imshow(MaskedtestCoin)
title('Masked Image', 'FontSize', fontSize)
% Measure areas and perimeters.
coinProps = regionprops(coinMask, testCoinImage, 'Area', 'Perimeter');
allAreas = [coinProps.Area]
allPerimeters = [coinProps.Perimeter]
range = [min(allAreas) max(allAreas)]
subplot(2, 2, 4);
bar(allAreas);
grid on;
title('Coin Areas', 'FontSize', fontSize)
%===========================================================================
function [BW, maskedImage] = segmentCoinFace(inputImage)
%segmentImage Segment image using auto-generated code from Image Segmenter app
% [BW, MASKEDIMAGE] = segmentImage(X) segments image X using auto-generated
% code from the Image Segmenter app. The final segmentation is returned in
% BW, and a masked image is returned in MASKEDIMAGE.
% Auto-generated by imageSegmenter app on 08-Jul-2023
%----------------------------------------------------
% Threshold image with global threshold
BW = imbinarize(im2gray(inputImage));
% Fill holes
BW = imfill(BW, 'holes');
% Find areas so we know what size blobs to exclude..
% props = regionprops(BW, 'Area');
% allAreas = sort([props.Area])
% Throw out blobs less than 2000 in area.
BW = bwareaopen(BW, 2000);
% Measure areas and perimeters.
labeledImage = bwlabel(BW);
coinProps = regionprops(BW, inputImage, 'PixelValues');
% Get the standard deviation of each coin
for k = 1 : numel(coinProps)
allSDs(k) = std(double(coinProps(k).PixelValues));
end
allSDs
% Get a mask of only where the StdDev is more than 15.
BW = ismember(labeledImage, find(allSDs >= 15));
% Create masked image.
maskedImage = inputImage;
maskedImage(~BW) = 0;
end
Valid Coin Segmentation
For this problem your code will need to create a mask which completely segments only the valid coins. Use the variable name validCoinMask.
The solutions to the previous assignments include a foreground mask with true pixel regions where any circular object is present (testCoinMask), and another coin face edge mask with true pixels only within the regions of valid coins (faceEdgeMask). Therefore, one approach to this task is to dilate the true pixel regions in faceEdgeMask to be greater than or equal to the size of the corresponding foreground regions in testCoinMask, and logically combine the result with testCoinMask to extract the valid coin regions. NOTE: Be careful not to dilate so far you overlap regions for blanks in the foreground mask. (See the project reading for more details.)
As before, you will be assessed using a randomly chosen selection from the three test images, so it is a good idea to test your algorithm on each of them in MATLAB.
% Read the test coin image.
testCoinImage = imread("testCoinImage3.png");
imshow(testCoinImage);
% Segment the coin image to get the testcoinMask and MaskedtestCoin.
[testcoinMask, MaskedtestCoin] = segmentCoin(testCoinImage);
% Shrink the coin mask to focus on the coin regions.
se = strel('disk', 20, 0);
testcoinMask = imfill(testcoinMask, 'holes');
testcoinMask = imerode(testcoinMask, se);
% Apply Gaussian filter to the masked coin image.
imgFilt = imgaussfilt(MaskedtestCoin, 0.5, 'Padding', 'circular', 'FilterDomain', 'frequency', 'FilterSize', 3);
% Detect edges using the Sobel operator.
faceEdgeMask = edge(imgFilt, 'sobel', 0.05, 'both');
% Eliminate edges outside the shrunken coin mask.
faceEdgeMask(~testcoinMask) = false;
% Dilate the faceEdgeMask to cover valid coin regions.
se_dilate = strel('disk', 20, 0);
dilated_faceEdgeMask = imdilate(faceEdgeMask, se_dilate);
% Combine the dilated faceEdgeMask with testcoinMask to get validCoinMask.
validCoinMask = testcoinMask & dilated_faceEdgeMask;
% Display the validCoinMask.
figure;
imshow(validCoinMask);
title('Valid Coin Mask');
% Segment Coin Function
function [testcoinMask, MaskedtestCoin] = segmentCoin(X)
X = im2gray(X);
testcoinMask = im2gray(X) > 200;
radius = 12;
decomposition = 4;
se = strel('disk', radius, decomposition);
testcoinMask = imclose(testcoinMask, se);
MaskedtestCoin = X;
MaskedtestCoin(~testcoinMask) = 0;
end
im ghetting the same error where im not able to mast all of the valid coins. please help me out here i have a deadline.

5 Comments

I agree with @Image Analyst's recommendations above. It would be a lot simpler to just create a mask that finds all coins, then identify the blank ones based on the variation within each region.
Instead of posting your homework question as an Answer to @Ahsan, start a new thread, tag it as homework, and attach your image. We can't determine why you're not able to get a mask of all the coins unless we have your image.
I'd also suggest asking your question in the course forum. You'll find the instructors are quite responsive, and will be more familiat with the techniques you are expected to use at this point in the course.
Can anyone help solve the ‘Valid Coin Segmentation’ problem for the MathWorks certification?

1 Comment

Please ask your questions in the course forum. It is activiely monitored by the course instructors.

This question is locked.

Asked:

on 12 Jul 2023

Locked:

on 13 Sep 2024

Community Treasure Hunt

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

Start Hunting!