An explanation for this MATLAB code snippet - matlab

Consider:
%# load a grayscale image
img = imread('coins.png');
%# display the image
figure
imshow(img,[]);
%# false-color
colormap('hot')
The above code is from here:
Infrared image processing in Matlab
But I don't understand how figure (what's the difference with/without it?) and colormap (how does it affect the already shown image?) work?

figure is not required, imshow just displays img on it. If a figure hadn't been opened, imshow would've created a new one.
The colormap colors the intensities of the image. The hot map colors values in increasing intensity with black, red, yellow, and white-hot. Another popular colormap is jet which has a number of interesting colors.
False colors
So the matrix you want to see has intensities which can have any range of values. For better visualization, the intensities are displayed in a range of colors or a set of false colors. Normally, a grayscale image will display an image is shades of grey, where white is maximum and black is minimum. False color is an extension of that concept with several colors in between (like jet) and an effect of metal being heated in hot.
Colormap at the pixel level
Suppose you have a matrix with pixel values ranging from [cmin xmax]. Now, normalize the values so that the range is [0,1]. Also, suppose you have a color map, such that a range of colors are mapped to some values from 0 to 1 (e.g. 0.5 is mapped to RGB(100,200,100))- then you get the false color mapping by finding the closest intensity in the map and display the corresponding color.
More on colormap in the MATLAB documentation. I've included some picture from that link here:
Jet
(source: mathworks.com)
Bone
alt text http://www.mathworks.com/access/helpdesk/help/techdoc/ref/bone_spine.gif

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

How to create an inverse gray scale?

I have an image with dark blue spots on a black background. I want to convert this to inverse gray scale. By inverse, I mean, I want the black ground to be white.
When I convert it to gray scale, it makes everything look black and it makes it very hard to differentiate.
Is there a way to do an inverse gray scale where the black background takes the lighter shades?
Or, another preferable option is to represent the blue as white and the black as black.
I am using img = rgb2gray(img); in MATLAB for now.
From mathworks site:
IM2 = imcomplement(IM)
Is there a way to do an inverse gray scale where the black
background takes the lighter shades?
Based on your image description I created an image sample.png:
img1 = imread('sample.png'); % Read rgb image from graphics file.
imshow(img1); % Display image.
Then, I used the imcomplement function to obtain the complement of the original image (as suggested in this answer).
img2 = imcomplement(img1); % Complement image.
imshow(img2); % Display image.
This is the result:
Or, another preferable option is to represent the blue as white and
the black as black.
In this case, the simplest option is to work with the blue channel. Now, depending on your needs, there are two approaches you can use:
Approach 1: Convert the blue channel to a binary image (B&W)
This comment suggests using the logical operation img(:,:,3) > 0, which will return a binary array of the blue channel, where every non-zero valued pixel will be mapped to 1 (white), and the rest of pixels will have a value of 0 (black).
While this approach is simple and valid, binary images have the big disadvantage of loosing intensity information. This can alter the perceptual properties of your image. Have a look at the code:
img3 = img1(:, :, 3) > 0; % Convert blue channel to binary image.
imshow(img3); % Display image.
This is the result:
Notice that the round shaped spots in the original image have become octagon shaped in the binary image, due to the loss of intensity information.
Approach 2: Convert the blue channel to grayscale image
A better approach is to use a grayscale image, because the intensity information is preserved.
The imshow function offers the imshow(I,[low high]) overload, which adjusts the color axis scaling of the grayscale image through the DisplayRange parameter.
One very cool feature of this overload, is that we can let imshow do the work for us.
From the documentation:
If you specify an empty matrix ([]), imshow uses [min(I(:)) max(I(:))]. In other words, use the minimum value in I as black, and the maximum value as white.
Have a look at the code:
img4 = img1(:, :, 3); % Extract blue channel.
imshow(img4, []); % Display image.
This is the result:
Notice that the round shape of the spots is preserved exactly as in the original image.

Converting a RGB image to grayscale based on the intensity of one color channel [duplicate]

This question already has an answer here:
Access RGB channels in an image in MATLAB
(1 answer)
Closed 6 years ago.
I'm working with images similar to this: a cell image, and I want to extract only the red-pink sections. As of now I'm using img(:,:,1) to pull out the red values but this produces a binary image. I wanted to know if there was a way to extract the "red" values and produce a grayscale image based on their degree of "redness" or intensity. Any help would be awesome.
You are likely visualizing the result using imshow which will automatically set the color limits of the axes to be between 0 and 1. Your image is RGB and the values of the red channel are going to range from 0 to 255. Because of this, if you only specify one input to imshow, you will get an image where all values > 1 will appear as white and all zero-values will be black. So your image isn't really binary, it just appears that way.
You want to either display your image with imagesc which will automatically scale the color limits to match your data:
imagesc(img(:,:,1));
colormap gray
Or you can specify the second input to imshow to cause it to also scale to fit your data range:
imshow(img(:,:,1), [])
The reason that this isn't an issue when you are visualizing all channels is that if you specify red, green, and blue channels, this is considered a true color image and all axes color limits are ignored.
The data you capture will be correct (and is grayscale), but the visualization may be incorrect. When trying to visualize a 2D matrix (same as your result img(:,:,1)), matlab applies the default colormap and the result is:
[x,y]=meshgrid(1:200, 1:200);
z=x.^2.*sin(y/max(y(:))*pi);
figure;imagesc(z);
If you want to avoid the applied jet colormap, either change the colormap:
colormap('gray')
or change your 2D matrix into a 3D one, explicitely specifying the colors to display (must be values between 0 and 1):
z3d = z(:,:,[1 1 1]); % more efficient than repmat
z3d = (z3d - min(z(:)))./range(z(:)); % make sure values in range [0; 1]
You see banding in the colormap version, because by default a colormap contains 64 different colors; the 3d matrix version doesn't have this problem as it directly displays the colors.
If I may add to your question, it seems to me you're simply trying to isolate and visualise the red, green, and blue fluorofores separately (or in combination). I specifically think this because you mention 'pink'.
It may be nicer to just isolate the channels:
>> F_red = F; F_red(:,:,[2,3]) = 0;
>> F_green = F; F_green(:,:,[1,3]) = 0;
>> F_blue = F; F_blue(:,:,[1,2]) = 0;
>> F_pink = F; F_pink(:,:,2) = 0;
Here's a subplot of the result:
Furthermore, you should know that the 'naive' way of producing a grayscale image does not preserve the 'luminosity' of colours as perceived by the human eye, since 'green' at the same intensity as 'red' and 'blue' will actually be perceived as brighter by the human eye, and similarly 'red' is brighter than 'blue'. Matlab provides an rgb2gray function which converts an rgb image to a grayscale image that correctly preserves luminance. This is irrelevant for your pure red, green, and blue conversions, but it may be something to think about with respect to a 'pink-to-grayscale' image. For instance, compare the two images below, you will see subtle contrast differences.
>> F_pinktogray_naive = mean(F(:,:,[1,3]), 3);
>> F_pinktogray_luminance = rgb2gray(F_pink);
A subplot of the two:
In a sense, you probably care more about the left (naive) one, because you don't care about converting the pink one to a gray one "visually", but you care more about the red and blue fluorofores being "comparable" in terms of their intensity on the grayscale image instead (since they represent measurements rather than a visual scene). But it's an important distinction to keep in mind when converting rgb images to grayscale.

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 detect colour from an image matlab?

we are doing a mat lab based robotics project.which actually sorts objects based on its color so we need an algorithm to detect specific color from the image captured from a camera using mat lab.
it will be a great help if some one can help me with it.its the video of the project
In response to Amro's answer:
The five squares above all have the same Hue value in HSV space. Selecting by Hue is helpful, but you'll want to impose some constraints on Saturation and value as well.
HSV allows you to describe color in a more human-meaningful way, but you still need to look at all three values.
As a starting point, I would use the rgb space and the euclidian norm to detect if a pixel has a given color. Typically, you have 3 values for a pixel: [red green blue]. You also have also 3 values defining a target color: [255 0 0] for red. Compute the euclidian norm between those two vectors, and apply a decision threshold to classify the color of your pixel.
Eventually, you want to get rid of the luminance factor (i.e is it a bright red or a dark red?). You can switch to HSV space and use the same norm on the H value. Or you can use [red/green blue/green] vectors. Before that, apply a low pass filter to the images because divisions (also present in the hsv2rgb transform) tend to increase noise.
You probably want to convert to the HSV colorspace, and detect colors based on the Hue values. MATLAB offers the RGB2HSV function.
Here is an example submission on File Exchange that illustrate color detection based on hue.
For obtaining a single color mask, first of all convert the rgb image gray using rgb2gray. Also extract the desired color plane from the rgb image ,(eg for obtaining red plain give rgb_img(:,:,1)). Subtract the given plane from the gray image........