Counting number of coloured pixels in an image - matlab

I have an image of a Jacaranda tree (jpeg) and i want to count the number of 'purple' pixels in this image using matlab.

The hard thing about this question is -> How do you define purple?
Before answering that lets introduce HSV color space.
In this color space, unlike in RGB, there is a single value that describes colors, while the others are saturation and "light" (see wikipedia or my answer here for more info about HSV). This means that just by looking at H we can know which color something is. The first thing we will do is put our image in HSV.
hsv_image = rgb2hsv(rgb_image)
Now we need to know which values of H are "purple". We can see a rough approximation of where purple is in this SO answer, where it is identified in around 300 degrees of Hue. If, instead, we look a bit deeper to the wikipedia page of Shades of purple*. There, we can see that the shades of purple listed are about 270-320 Hue values.
If we like this approximation, then we can just select the pixels of the image with that amount of H by
H=hsv_image(:,:,1);
and then just select the ones that are in the desired range
purple=H<320 && H> 270;
Or in just one go
purple=hsv_image(:,:,1)<320 && hsv_image(:,:,1)> 270;
Then we just need to count.
N_purple=sum(purple(:))
*If you were asking for gray the wikipedia page would be confusing

Related

What's the most efficient way of identifying items of a specific shade of colour in an image with matlab?

im trying to identify a specific shade of green leaves (e.g. navy green) from the attached image. how do i do that in the most efficient way? So far, i'm converting the RGB to HSV and then thresholding the image based on some specific range of saturation and value that will isolate my desired shade. it's working on some images and it's just all over the place on others. i want something that can isolate a specific shade of green in any different image that has slightly different saturation and value (e.g. if the picture was taken with too much light)
Image link
pic=imread('image.jpg');
q=rgb2hsv(pic);
H=q(:,:,1);
S=q(:,:,2);
V=q(:,:,3);
thresh=S>0.6111 & S<0.6666 & V>0.3888 & V<0.4583;
st=strel('diamond',20);
w=imdilate(thresh,st);
comps=bwconncomp(w,8);
num=comps.NumObjects;
fprintf('The number of leaves is %i',num)
% then i try to have some pointers on the image to show me where matlab has identified the the shade.
m = regionprops(w,'centroid');
boxes = cat(1, m.Centroid);
imshow(pic)
hold on
plot(boxes(:,1),boxes(:,2), 'b*')
hold off
Your help will be highly appreciated.
Either the HSV color space (hey, S is saturation and V value), where H will give you the hue,or CIE-Lab color space, where euclidean distance will give you how close 2 specific pixel are to each other in color.
This answer explains how to do it for HSV: Segment pixels in an image based on colour (Matlab)
Using combined with CIE-LAB may help if the colors are very close together (like the greens in each leaf), but you should give HSV a shot

Histogram after thresholding

I have an image and I apply thresholding to it to apply binary mask.I draw histogram before and after the thresholding process.The histograms look like below.
The second figure which is after thresholding,doesn't show any peaks.Is that mean,my thresholding is wrong.Can anyone please explain these histograms.
Update
Image after thresholding
To summarize Sardar's comment, the horizontal range of your plot is tight. Simply loosen the range a bit so you can see the result better. Doing xlim([-0.5 1.5]); will certainly do that and we can see that in the last figure of your update. How you interpret the histogram... well, for black and white images, examining the histogram is never meaningful because there are only two possible intensities to examine - 0 and 1. Histograms usually give a glimpse as to the contrast of the image. If the histogram is spread out, this usually gives an indication that the image has high contrast. However, if the histogram is within a small range this usually means the image is poor contrast.
Remember that the histogram simply count the occurrence of instances in a data set. In this case, we are counting how many times we see 0 and 1 in the image. Referring to your last plot, this means that approximately 9000 pixels that are intensity 0 and approximately 4000 pixels that are intensity 1. This gives absolutely no indication as to the contrast or the spread of the intensities in your image. because there are only two possible intensities that are seen in the image. As such, to answer your question in such a long-winded way, the answer is that you can't really interpret anything.
The only thing I can possible suggest is that it tells you the ratio of object pixels to background pixels and could indicate a measure of quality. Usually when we determine what is an object and what are background pixels, we would expect that there would be more background pixels than object pixels to be able to discern this from the background. Therefore, the more black pixels you have the better it may be. That being said, I can't really say more unless you actually show us what your image looks like after you threshold it.

Block artifact in converting RGB 2 HSV

I would like to convert an image from RGB space to HSV in MATLAB and use the Hue.
However, when I use 'rgb2hsv' or some other codes that I found in the internet the Hue component has block artifacts. An example of the original image and the block artifact version are shown below.
Original
Hue
I was able to reproduce your error. For those of you who are reading and want to reproduce this image on your own end, you can do this:
im = imread('http://i.stack.imgur.com/Lw8rj.jpg');
im2 = rgb2hsv(im);
imshow(im2(:,:,1));
This code will produce the output image that the OP has shown us.
You are directly using the Hue and showing the result. You should note that Hue does not have the same interpretation as grayscale intensity as per the RGB colour space.
You should probably refer to the definition of the Hue. The Hue basically refers to how humans perceive the colour to be, or the dominant colour that is interpreted by the human visual system. This is the angle that is made along the circular opening in the HSV cone. The RGB colour space can be represented as all of its colours being confined into a cube. It is a 3D space where each axis denotes the amount of each primary colour (red, green, blue) that contributes to the colour pixel in question. Converting a pixel into HSV, also known as Hue-Saturation-Value, converts the RGB colour space into a cone. The cone can be parameterized by the distance from the origin of the cone and moving upwards (value), the distance from the centre of the cone moving outwards (saturation), and the angle around the circular opening of the cone (hue).
This is what the HSV cone looks like:
Source: Wikipedia
The mapping between the angle of the Hue to the dominant / perceived colour is shown below:
Source: Wikipedia
As you can see, each angle denotes what the dominant colour would be. In MATLAB, this is scaled between [0,1]. As such, you are not visualizing the Hue properly. You are using the Hue channel to directly display this result as a grayscale image.
However, if you do a scan of the values within this image, and multiply each result by 360, then refer to the Hue colour table that I have shown above, this will give you a representation of what the dominant colours at these pixel locations would be.
The moral of this story is that you can't simply use the Hue and visualize that result. Converting to HSV can certainly be used as a pre-processing step, but you should do some more processing in this domain before anything fruitful is to happen. Looking at it directly as an image is pretty useless, as you have seen in your output image. What you can do is use a colour map that derives a relationship between hue and colour like in the Hue lookup map that I showed you, and you can then colourize your image but that's really only used as an observational tool.
Edit: July 23, 2014
As a bonus, what we can do is display the Hue as an initial grayscale image, then apply an appropriate colour map to the image so we can actually visualize what each dominant colour at each location looks like. Fortunately, there is a built-in HSV colour map that is pretty much the same as the colour lookup map that I showed above. All you would have to do is do colormap hsv right after you show the Hue channel. We can show the original image and this colourized image side-by-side by doing:
im = imread('http://i.stack.imgur.com/Lw8rj.jpg');
im2 = rgb2hsv(im);
subplot(1,2,1);
imshow(im); title('Original Image');
subplot(1,2,2);
imshow(im2(:,:,1)); title('Hue channel - Colour coded');
colormap hsv;
This is what the figure looks like:
The figure may be a bit confusing. It is labelling the sky as being blue as the dominant colour. Although this is confusing, this makes actual sense. On a clear day, the sky is blue, but the reason why the sky appears gray in this photo is probably due to the contributions in saturation and value. Saturation refers to how "pure" the colour is. As an example, true red (RGB = [255,0,0]), means that the saturation is 100%. Value refers to the intensity of the colour. Basically, it refers to how dark or how light the colour is. As such, the saturation and value would most likely play a part here which would make the colour appear gray. The few bits of colour that we see in the image is what we expect how we perceive the colours to be. For example, the red along the side of the jet carrier is perceived as red, and the green helmet is perceived to be green. The lower body of the jet carrier is (apparently) perceived to be red as well. This I can't really explain to you, but the saturation and value are contributing to the mix so that the overall output colour is about a gray or so.
The blockiness that you see in the image is most likely due to JPEG quantization. JPEG works great in that we don't perceive any discontinuities in smooth regions of the image, but the way the image is encoded is that it reconstructs it this way... in a method that will greatly reduce the size it takes to save the image, but allow it to be as visually appealing as if you were to look at the RAW image.
The moral of the story here is that you can certainly use Hue as part of your processing chain, but it is not the entire picture. You will probably need to use saturation or value (or even both) to help you discern between the colours.

How to Count number Objects in an Image identify by Color in Matlab

I want to count number of Objects in an Image identify by each color.
Example: I want to count yellow rices or green rices in the image.
Would you please give me some tip to do it?
You've taken this image from the rice demonstration that ships with MATLAB's Image Processing Toolbox. If you read through the demo, you already have some code that will isolate each rice grain individually - that's how the image was created.
As for counting the number of grains that have a particular color such as yellow or green, again read through the demo: it's clear that the rice grains are not colored with a small set of discrete colors such as yellow or green (or orange or pink). Rather, the rice grain colors have been specifically created so that they are equally spaced throughout the colormap spring.
So to proceed with your task you're going to have to provide some definition of 'yellow' or 'green', perhaps in terms of being within a particular range of RGB values.
Having done this, you can then use the variable labeled (that is constructed for you in the demo) together with the regionprops command, to give you a list of the pixels that are within each rice grain boundary. Simply compare those pixels to your definitions of yellow or green, and you're there.
assuming you have an image in matrix a (sized m*n*3), and you want to find the number of objects with color [r,g,b].
first, select only pixels with the correct color:
bb = (a(:,:,1) == r & a(:,:,2) == g &a(:,:,3) == b);
Than:
[~,num] = bwlabel(bb,8)
num is the number of objects.
This is best done by working in a different colorspace than the RGB one (think HSV, Lab*, ..).
Steve Eddins posted a series of articles showing an example how to segment objects of certain color from an image (green M&Ms in his case):
What color is green?
Two-Dimensional Histograms
a* and b*
Freehand segmentation in the a*-b* plane
More on segmenting in a*-b* space

Filtering out pixels in the green channel with MATLAB, etc

It's from Stack Overflow question How do I calculate the area under a curve in an image with MATLAB?, but I'm also interested in this.
How do I filter out pixels not in the green channel?
And how do I select a point which is inside a closed box with MATLAB?
Alt text http://internationalpropertiesregistry.com/Server/showFile.php?file=%2FUpload%2Fstatistics.gifc49ca28823a561a41d09ef9adbb5e0c5.gif
For your two questions:
Colored pixels have red, green, and blue color components. Selecting pixels based on their color involves selecting how much of each RGB component is present in the pixel. For example, a pure white pixel has each color component at its maximum (1 if the image type is double precision, 255 if the image type is uint8). You can look at my solution to the referenced question to see one way you can select pixels based on their RGB components. You can also check out this MATLAB documentation for more information about images and their data types.
One way to select a point is to let the user select it using the GINPUT function. For example, the following will let the user select 1 point from the current axes, returning the x and y coordinates where they click:
[x,y] = ginput(1);
For the first question, #gnovice's answer should suffice.
For the second question: Use a Monte Carlo approach: have the algorithm choose a random pixel using RANDI (you may want to search within, say, 20 pixels of the center of the image to avoid problems with the border). If it's a green pixel, you try again. If it's a white pixel, you are inside one of the squares.