You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How can I determine the cluster of pixels in an image that are red or green and quantify how many of the clusters are green or red?
21 views (last 30 days)
Show older comments
I have an image that has small red or green circles per image. Each image could have up to 30 or so red or green circles per image. I have to count them manually in order to quantify them and it can be tedious with more than 50 images. Is there a way to classify the circles as red or green and then quantify them by color automatically? Thanks!
42 Comments
Walter Roberson
on 17 Jun 2022
First you have to define what is Red, and what Green, and what is neither. This turns out to be surprisingly difficult.
Neo
on 17 Jun 2022
Well how can I try? It is a black image with either red or blue cirlces in them, not a color map. Thanks!!
Walter Roberson
on 17 Jun 2022
How do you know that any given circle is red or blue or green?
It turns out that what humans classify as red or blue or green or black is not as simple as looking to see which of the RGB components is greatest.
Neo
on 17 Jun 2022
You can see with your eyes that some circles are red or green. Is that sufficient? I can even give the code a base rgb classification value so that it can classify what I want as green and otherwise red. I just do not know the code to do that.
Walter Roberson
on 17 Jun 2022
Consider [0 1 0]/256. What color is that? Is it green or is it black? Look at it with your eyes: can you reliably visually tell it apart from [0 0 0]/256 when the two are not side by side?
Consider [11 5 11]/256 .Is that red or blue or something else?
There are colors that humans tend to classify as blue when the green component is slightly more than the blue. Do you want the "look with your eyes" classification (blue) or do you want a more mechanical classification?
If you can state a rule or set of rules about how to classify pixels as to their color then we can help you implement it.
Image Analyst
on 17 Jun 2022
"You can see with your eyes that some circles are red or green." <== No, we can't. Why not? Because you never read any posting guidelines and so you keep forgetting to post your image.
If you have any more questions, then attach your image and code to read it in with the paperclip icon after you read this:
In the meantime, try the Color Thresholder app on the Apps tab of the tool ribbon.
Image Analyst
on 17 Jun 2022
Did you try the Color thresholder like I suggested? If not, why not? If you still need help, say so.
Neo
on 18 Jun 2022
Yes, I have. I ran into a problem with my matlab version and have to update it on monday. i did go to examples as you suggested Analyst, and color thresholder looks promising!! But I did not see a way to quantify the regions of interest automatically, what do you suggest? Thanks!
Neo
on 21 Jun 2022
Edited: Neo
on 21 Jun 2022
@Walter Roberson where would I place that bit of code in this autogenerated code that the color thresholder app provide me? @Image Analyst
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 21-Jun-2022
%------------------------------------------------------
% Convert RGB image to chosen color space
I = rgb2hsv(RGB);
% Define thresholds for channel 1 based on histogram settings
channel1Min = 0.000;
channel1Max = 0.611;
% Define thresholds for channel 2 based on histogram settings
channel2Min = 0.779;
channel2Max = 1.000;
% Define thresholds for channel 3 based on histogram settings
channel3Min = 0.113;
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
Thank you.
Walter Roberson
on 22 Jun 2022
The code I posted is not for use with the color thresholder. It is code that, by itself, only answers the question of who many circles there are -- circles of any brighter color.
Walter Roberson
on 22 Jun 2022
filename = 'https://www.mathworks.com/matlabcentral/answers/uploaded_files/1036195/image.jpeg';
YourRGBImage = imread(filename);
bw = im2bw(YourRGBImage);
bw = bwareafilt(bw, [10 inf]);
whos bw
Name Size Bytes Class Attributes
bw 512x512 262144 logical
[~, numcircles] = bwlabel(bw) ;
imshow(YourRGBImage)
imshow(bw)
numcircles
numcircles = 9
This code makes no attempt to separate adjacent circles.
Image Analyst
on 22 Jun 2022
Walter, please move to an Answer. @Neo this will work. If your images are only one color, red or green, then you can just binarize with imbinarize (like Walter's code) and don't need to worry about the Color Thresholder. You only need to use that if your images have multiple colors in them. If you want additional measurements beyond the count, like area or brightness or diameter, then you can use regionprops.
Walter Roberson
on 22 Jun 2022
imbinarize turned out to be wrong for rgb, which is why I show im2bw here.
Color thresholding would be useful for the case where you need to distinguish colors. If you only need the total or each image only has one known class then the method I show here is good enough to count blobs. If you need to separate touching blobs then more work is needed.
Neo
on 22 Jun 2022
Thanks @Image Analyst and @Walter Roberson you two should be embedded in the matlab complier in some way because you both are historic. Thank you so much.
Image Analyst
on 22 Jun 2022
They're working on getting a cast of me for the life-sized bronze statue of me they're going to make and install near the main entrance of their main Headquarters in Natick MA.
Neo
on 23 Jun 2022
Edited: Walter Roberson
on 24 Jun 2022
My error:
Error in counting (line 1)
MyRGBImage = imread('TESTC.jpg');
My code:
MyRGBImage = imread('TESTC.jpg');
bw = im2bw(MyRGBImage);
bw = bwareafilt(bw, [10 inf]);
whos bw
[~, numcircles] = bwlabel(bw) ;
imshow(MyRGBImage)
imshow(bw)
numcircles
Do you guys see the problem?
Image Analyst
on 23 Jun 2022
Edited: Image Analyst
on 23 Jun 2022
Line 1 is the imread() line. You forgot to include the entire error message so I don't know what it could be. It could be that you don't have the Image Processing Toolbox, or it could be that you don't have that file.
Hopefully now you appreciate my code, which is more robust. I know it's a lot longer than yours or Walter's, and maybe that scared you off, but there's a reason for why it's longer. More comments, and more checks for things like if the file exists or not. Plus more display code so you can see what's going on.
Neo
on 23 Jun 2022
@Image Analyst Thank you! I actually did not see your answer until after I accepted Walter's. I do appreciate it!! Then I saw your comment that suggested to accept Walter's comment (you wrote move to answer). I wish that I could accept both!
My full error:
>> counting
Error using imread>get_full_filename
File "TESTC.jpg" does not exist.
Error in imread (line 371)
fullname = get_full_filename(filename);
Error in counting (line 1)
MyRGBImage = imread('TESTC.jpg');
I went to my current folder and imported the data, it appeared in work space then i renamed it in the workspace as TESTC. I am not sure what my error could have been. Here is a screenshot that I hope can help.
Image Analyst
on 23 Jun 2022
Edited: Image Analyst
on 23 Jun 2022
Show the current folder panel also. It looks like that filename is just not in there.
You can have variable names the same as the base filename if you want (no dot or extension though). So having a variable TESTA and a file TESTA.JPG is fine.
You can award 2 reputation points (same as Accepting) by clicking on the "Vote" icon. Thanks in advance. 🙂
Neo
on 23 Jun 2022
Is there a way to count cirlces in multiple images then quantify the number of circles?
Eg. I have 30 seperate images with circles of the same color. I want to import them all into the workspace then read them all into the code, quantify the circles in each image, then add them together and output the final count.
I think something like:
for n=1:30
images{n} = imread(bwlabel(bw));
end
will work but I am not sure where to insert it in either code, I am still troubleshooting on my own but I am open to feedback in order to be more efficient!
Image Analyst
on 23 Jun 2022
To process a sequence of files, see the FAQ
Or adapt the attached program.
Neo
on 24 Jun 2022
Edited: Walter Roberson
on 24 Jun 2022
% Read files mat1.mat through mat20.mat, file1.txt through file20.txt,
% and image1.jpg through image20.jpg. Files are in the current directory.
% Use fullfile() if you need to prepend some other folder to the base file name.
% Adapt to use which ever cases you need.
for k = 1 : 2
% OPTION 2: Create an image filename, and read it in to a variable called imageData.
MyRGBImage = strcat('hi1', num2str(k), '.jpg');
if isfile(MyRGBImage)
imageData = imread(MyRGBImage);
bw = im2bw(MyRGBImage);
bw = bwareafilt(bw, [10 inf]);
whos bw
[~, numcircles] = bwlabel(bw);
imshow(MyRGBImage)
imshow(bw)
numcircles
count = sum((numcircles), 2);
else
fprintf('File %s does not exist.\n', MyRGBImage);
end
end
This is what I have adapted, what do you think? You can just give me suggestions instead of the answer if you'd prefer. i'd like to figure it out on my own but I've been stuck on this part for a minute. Thank you!
Image Analyst
on 24 Jun 2022
You took the wrong snippet of code from the FAQ. Use the other snippet that calls dir(). Then take my answer and put all that into a function. Then call the function, passing in rgbImage and passing out any results you want, into the center of the for loop.
Neo
on 24 Jun 2022
@Walter Roberson since I used some of your code in the program what do you suggest?
@Image Analyst is it possible to use the code that I have and troubleshoot?
Walter Roberson
on 24 Jun 2022
dinfo = dir('*.jpg');
filenames = {dinfo.name};
numfiles = length(filenames);
count = zeros(numfiles, 1);
for K = 1 : numfiles
MyRGBImage = filenames{K};
imageData = imread(MyRGBImage);
bw = im2bw(imageData);
bw = bwareafilt(bw, [10 inf]);
[~, numcircles] = bwlabel(bw);
circle_count(K) = numcircles;
end
[~, filename, ~] = fileinfo(filenames);
info_table = table(filename, circle_count);
finalcount = sum(circle_count);
disp(info_table)
Image Analyst
on 25 Jun 2022
Sometimes a min size of 10 gives noise. That's why I tested it and decided a min size of 100 would probably be best. Displaying the mask would alert you to that. Neo don't be afraid of code just because it's longer because it has things in there to help you, like comments and display functions.
Neo
on 25 Jun 2022
@Walter Roberson Thank you! I will try this.
@Image Analyst Okay, I will try it out I do admire you a lot so I appreciate your encouragement.
Neo
on 25 Jun 2022
@Walter Roberson can you add a short comment to your code, i am not sure why you have a zeros command there...
Image Analyst
on 25 Jun 2022
The zeros() call is there to preallocate space for the counts array. It will make the loop run slightly faster and avoid the orange squiggle suggesting that you do that to avoid re-allocating the array on every iteration.
I suggest you go through the code yourself and learn what each function does (bwareafilt, bwlabel, im2bw, etc.) and add a comment yourself. It will help you learn it better.
Neo
on 6 Jul 2022
hey guys, when I run the loop code I get the following error. Do you know why?
Unrecognized function or variable 'fileinfo'.
Error in loopcount (line 13)
[~, filename, ~] = fileinfo(filenames);
The only input I used was test1.jpg for the image. I'm an apprentice but I am getting the hang of this! Do you have an idea of why i am getting this error? Thanks!
Image Analyst
on 6 Jul 2022
Neo
on 6 Jul 2022
I want to make this loop work such that it is able to count the blobs individually then add them together.
I changed fileinfo to fileparts but then I get this second error:
Error using table
All table variables must have the same number of rows.
Error in loopcount (line 14)
info_table = table(filename, circle_count);
Neo
on 6 Jul 2022
And when I use imfinfo my error is the following:
Error using imfinfo
Too many output arguments.
Error in loopcount (line 13)
[~, filename, ~] = imfinfo(filenames);
Image Analyst
on 6 Jul 2022
Attach loopcount.m
And what is your intent when you try to do this?
[~, filename, ~] = fileinfo(filenames);
Did by chance you want to get one filename from a list of filenames, like
filename = filenames{someIndex};
Neo
on 6 Jul 2022
here is loopcount:
dinfo = dir('.jpg');
filenames = {dinfo.name};
numfiles = length(filenames);
count = zeros(numfiles, 1);
for K = 1 : numfiles
MyRGBImage = filenames{K};
imageData = imread(MyRGBImage);
bw = im2bw(imageData);
bw = bwareafilt(bw, [10 inf]);
[~, numcircles] = bwlabel(bw);
circle_count(K) = numcircles;
end
[~, filename, ~] = fileparts(filenames);
info_table = table(filename, circle_count);
finalcount = sum(circle_count);
disp(info_table)
yes I think that was the intent.
Overall, the code is meant to read multiple images automatically, count the blebs in each image individually and then add them together, finally output the sum.
Thank you!!
Neo
on 6 Jul 2022
Yes, but once I upload my images (just two to test) it outputs:
filename circle_count
___________ ____________
{1×29 cell} 1×29 double
Accepted Answer
Walter Roberson
on 23 Jun 2022
filename = 'https://www.mathworks.com/matlabcentral/answers/uploaded_files/1036195/image.jpeg';
YourRGBImage = imread(filename);
bw = im2bw(YourRGBImage);
bw = bwareafilt(bw, [10 inf]);
whos bw
Name Size Bytes Class Attributes
bw 512x512 262144 logical
[~, numcircles] = bwlabel(bw) ;
imshow(YourRGBImage)
imshow(bw)
numcircles
numcircles = 9
More Answers (2)
Image Analyst
on 22 Jun 2022
Try this. It should work for any color spots.
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 = 'green spots.png';
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 demo image.
rgbImage = imread(fullFileName);
% Get the dimensions of the image.
[rows, columns, numberOfColorChannels] = size(rgbImage)
% Crop off screenshot stuff
% rgbImage = rgbImage(132:938, 352:1566, :);
% Display image.
subplot(2, 2, 1);
imshow(rgbImage, []);
impixelinfo;
axis on;
caption = sprintf('Original Color 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.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0 0.05 1 0.95]);
% 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;
% Take one of the color channels, whichever one seems to have more contrast.
grayImage = max(rgbImage, [], 3);
% Crop away white surrounding frame.
% It's probably there because it's not the original image but came from a screenshot of a figure.
grayImage = grayImage(33:385, 123:475);
% Get the updated dimensions of the image.
[rows, columns, numberOfColorChannels] = size(grayImage)
% Display the image.
subplot(2, 2, 2);
imshow(grayImage, []);
title('Gray Scale Image', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
axis('on', 'image');
drawnow;
%=======================================================================================
% Show the histogram
subplot(2, 2, 3);
imhist(grayImage);
grid on;
caption = sprintf('Histogram of Gray Scale Image')
title(caption, 'FontSize', fontSize, 'Interpreter', 'None');
xlabel('Gray Level', 'FontSize', fontSize)
ylabel('Count', 'FontSize', fontSize)
%=======================================================================================
% Threshold the image to get the disk.
lowThreshold = 43;
highThreshold = 255;
% Use interactive File Exchange utility by Image Analyst to to the interactive thresholding.
% https://www.mathworks.com/matlabcentral/fileexchange/29372-thresholding-an-image?s_tid=srchtitle
% [lowThreshold, highThreshold] = threshold(114, 255, grayImage);
mask = grayImage >= lowThreshold & grayImage <= highThreshold;
xline(lowThreshold, 'Color', 'r', 'LineWidth',2);
xline(highThreshold, 'Color', 'r', 'LineWidth',2);
% Find out the size of all the blobs so we know what size to use when filtering with bwareaopen.
props = regionprops(mask, 'Area');
allAreas = sort([props.Area]);
% Now do clean up by hole filling, and getting rid of small blobs.
mask = bwareaopen(mask, 100); % Take blobs larger than 100 pixels only.
% Display the color segmentation mask image.
subplot(2, 2, 4);
imshow(mask, []);
title('Final Mask', 'FontSize', fontSize, 'Interpreter', 'None');
impixelinfo;
axis('on', 'image');
drawnow;
% Find out the size of all the remaining blobs.
props = regionprops(mask, 'Area');
allAreas = sort([props.Area])
areaFraction = sum(allAreas) / numel(mask)
uiwait(helpdlg('Done!'));
james
on 8 Jul 2022
Does the classifier make clusters on red,green and blue channel separately? And if it does- lets say the cluster are formed at intensities 40,80,90,135 for red 60,90,130,240 for green 20,40,60,90 for blue.
4 Comments
Image Analyst
on 8 Jul 2022
@james looking back up, I see only a segmentation for green. It's possible to do it for 3 colors but if you want those separated, you'd have to do it 3 separate times, one for each color. This is the best way
Or you could just do it for one combined image but if the red and green blobs touched, it would consider it one blob. But then to determine what color each blob is you'd have to ask regionprops for 'MeanIntensity', three times once for each color channel, and then figure out the blob color by looking at the 3 intensities. This is not as good as the first method I mentioned.
Or you could train a discriminant classifier and just work on the color image. This would produce a classified image where background pixels have value 0, red pixels have value 1, green pixels have value 2, and blue pixels have value 3. Try out my attached demo.
You might also use a K nearest neighbor classifier.
Neo
on 16 Aug 2022
This code will work for any segmentation besides green correct? As long as its in a single channel?
Image Analyst
on 16 Aug 2022
@Neo the classification code I gave will work for any color (not just green). The color does not even have to lie solely in one particular color channel. For example the color could be [.3, 0.5, 0.8] and it would still find it because you train it by telling it (by outlining a region) what color(s) you are looking for. THe discriminant analysis is a statistical color classifier. If you just want to use known color ranges, that are fixed and known in advance, then you might want to use the Color Thresholder app because with that tool you do not need to outline any regions to tell it the colors. You tell it the colors by thresholding the histograms.
See Also
Tags
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom(English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)