How to count the number of object by colour ?

58 views (last 30 days)
thar on 15 Sep 2016
Commented: Image Analyst on 21 Sep 2016
I want to count the number of grains of two different colors in this image separately. Also is there a way to make the whole background to yellow without changing colors of grains because I want to count them separately.

Answers (3)

Image Analyst
Image Analyst on 16 Sep 2016
Here's something to get you started. Still needs some work to clean up some misidentified pixels and noise, but it's a very good start for you. It background corrects the image with CLAHE (imadapthisteq function), then converts to LAB color space and uses kmeans to classify the image into 3 colors.
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 = 20;
% Check that user has the Image Processing Toolbox installed.
hasIPT = license('test', 'image_toolbox'); % license('test','Statistics_toolbox'), license('test','Signal_toolbox')
if ~hasIPT
% User does not have the toolbox installed.
message = sprintf('Sorry, but you do not seem to have the Image Processing Toolbox.\nDo you want to try to continue anyway?');
reply = questdlg(message, 'Toolbox missing', 'Yes', 'No', 'Yes');
if strcmpi(reply, 'No')
% User said No, so exit.
% Read in a standard MATLAB color demo image.
folder = pwd; % Determine where demo folder is (works with all versions).
baseFileName = 'a.jpg';
% 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);
rgbImage = imread(fullFileName);
% Get the dimensions of the image. numberOfColorBands should be = 3.
[rows, columns, numberOfColorChannels] = size(rgbImage);
% Display the original color image.
subplot(3, 3, 1);
axis on;
title('Original Color Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'Outerposition', [0, 0, 1, 1]);
% Extract the individual red, green, and blue color channels.
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
redChannel = adapthisteq(redChannel, 'clipLimit',0.02,'Distribution','rayleigh');
greenChannel = adapthisteq(greenChannel, 'clipLimit',0.02,'Distribution','rayleigh');
blueChannel = adapthisteq(blueChannel, 'clipLimit',0.02,'Distribution','rayleigh');
% Recombine separate color channels into a single, true color RGB image.
rgbImage = cat(3, redChannel, greenChannel, blueChannel);
subplot(3, 3, 2);
axis on;
title('Background corrected Color Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Convert to grayscale.
grayImage = rgb2gray(rgbImage);
% It's still a bit noisy from the CLAHE operation so do a median filter
grayImage = medfilt2(grayImage, [15, 15]);
subplot(3, 3, 3);
axis on;
title('Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Take the histogram
subplot(3, 3, 4);
xlabel('Gray Level', 'FontSize', fontSize);
ylabel('Count', 'FontSize', fontSize);
grid on;
ax = gca
ax.XTick = [0:16:255];
ax.GridAlpha = 0.75;
% Binarize the image
binaryImage = grayImage < 112;
% Just keep the larger blobs larger than 1400
binaryImage = bwareafilt(binaryImage, [1400, inf]);
% Fill Holes
binaryImage = imfill(binaryImage, 'holes');
% Get rid of any blobs touching the border of the image.
binaryImage = imclearborder(binaryImage);
subplot(3, 3, 5);
axis on;
title('Binary Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Label
[labeledImage, numBlobs] = bwlabel(binaryImage);
% Let's assign each blob a different color to visually show the user the distinct blobs.
coloredLabels = label2rgb (labeledImage, 'hsv', 'k', 'shuffle'); % pseudo random color labels
% coloredLabels is an RGB image. We could have applied a colormap instead (but only with R2014b and later)
subplot(3, 3, 6);
axis image; % Make sure image is not artificially stretched because of screen's aspect ratio.
caption = sprintf('Pseudo colored labels, from label2rgb().\nBlobs are numbered from top to bottom, then from left to right.');
title(caption, 'FontSize', fontSize);
% Get all the blob properties. Can only pass in originalImage in version R2008a and later.
blobMeasurements = regionprops(labeledImage, 'Area');
allAreas = sort([blobMeasurements.Area], 'descend')
% Dilate some and mask out the original image.
binaryImage = imdilate(binaryImage, true(9));
% Find the mean gray level of the background.
backgroundMask = ~binaryImage;
meanGL = mean(grayImage(backgroundMask))
% Make color channels the mean where the background is so we can use kmeans() or rgb2ind().
redChannel(backgroundMask) = meanGL;
greenChannel(backgroundMask) = meanGL;
blueChannel(backgroundMask) = meanGL;
% Recombine separate color channels into a single, true color RGB image.
rgbImage = cat(3, redChannel, greenChannel, blueChannel);
subplot(3, 3, 7);
title('Masked RGB Image', 'FontSize', fontSize, 'Interpreter', 'None');
% Now do kmeans color classification
labImage = rgb2lab(rgbImage);
[rows, columns, numberOfColorChannels] = size(labImage);
labList = reshape(labImage, (rows * columns), 3);
nColors = 3;
% repeat the clustering 3 times to avoid local minima
[cluster_idx, cluster_center] = kmeans(labList, nColors,...
'distance','sqEuclidean', 'Replicates',3);
% Show the results.
subplot(3, 3, 8:9);
classifiedImage = reshape(cluster_idx, rows, columns);
imshow(classifiedImage, []);
title('Image labeled by cluster index');
Image Analyst
Image Analyst on 21 Sep 2016
If we're done here and this works for you, can you Vote and/or "Accept this answer"?

Sign in to comment.

Mikael Erkkilä
Mikael Erkkilä on 15 Sep 2016
This is basically image segmentation. So I would encode the colors into grayscale and use the bwconncomp function as described in

Image Analyst
Image Analyst on 15 Sep 2016
It looks like you've already segmented the grains, though badly. Most likely you'd benefit from background correction. Just take a shot with no grains there, then divide the image with grains by the image without grains. Then threshold, clean up noise some with functions like bwareafilt(), and call bwlabel() to get the count.
If you need to segment the already segmented and pseudocolored image, just find the RGB values of the two grain colors, for example by calling impixelinfo() and mousing over the grains. Then you can extract the color channels:
% Extract the individual red, green, and blue color channels.
redChannel = rgbImage(:, :, 1);
greenChannel = rgbImage(:, :, 2);
blueChannel = rgbImage(:, :, 3);
Then for grain color #1, create a binary mask
mask1 = redChannel == r1 & greenChannel == g1 & blueChannel == b1;
Then get rid of things less than 10 pixels or whatever
mask1 = bwareafilt(mask, [10, inf]);
Then get rid of blobs touching the border
mask = imclearborder(mask);
Then count
[labeledImage, count1] = bwlabel(mask1);
Repeat for second color. But don't do that. You're far, far better off getting a good segmentation in the first place (like by background correction) than you are segmenting an already segmented image.
thar on 16 Sep 2016
could you please tell me how to define the R,G and B ?
Grains RBG values are [0 0 225] and [0 225 255]
Here is the code I used
title('Original Image')
I = rgb2gray(i);
title('Grayscale Image')
j = medfilt2(I);
thresh = multithresh(j,2);
seg_I = imquantize(j,thresh);
RGB = label2rgb(seg_I);
title('Multi threshold Image')
% Extract the individual red, green, and blue color channels.
redChannel = RGB(:, :, 1);
greenChannel = RGB(:, :, 2);
blueChannel = RGB(:, :, 3);
mask1 = redChannel == r1 & greenChannel == g1 & blueChannel == b1;
mask2 = bwareafilt(mask, [10, inf]);

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!