Grayscale image and L*a*b space in MATLAB - matlab

I have a bunch of images, the vast majority of which are color (rgb) images. I need to apply some spatial features in the three different channels of their Lab color space. The conversion from RGB Color space to Lab color space is straightforward through rgb2gray. However, this naturally fails when the image is grayscale (consists of one channel only, with the numerical representation being a double, uint8, anything really).
I am familiar with the fact that the "luminance" (L) channel of the Lab color space is essentially the grayscaled original RGB image. This question, however, is of a different nature; what I'm asking is: Given an image that is already grayscale, I trivially get the L channel in Lab color space. What should the a and b channels be? Should they be zero? The following example, using the pre-build "peppers" image, shows the visual effect of doing so:
I = imread('peppers.png');
figure; imshow(I, []);
Lab = rgb2gray(I);
Lab(:, :, 2) = 0;
Lab(:, :, 3) = 0;
figure; imshow(Lab, []);
If you run this code, you will note that the second imshow outputs a reddish version of the first image, resembling an old dark room. I admit to not being knowledgeable about what the a and b color channels represent in order to understand how I should deal with them in grayscale images, and was looking for some assistance.

An XY Type of Question.
IN CIELAB, a* and b* at 0 means no chroma: i.e. it's greyscale.
BUT WAIT THERE'S MORE! If you're having problems it's because that's not the actual question you need answered:
Incorrect Assumptions
First off, no, The L* of L*a*b* is NOT Luminance, and it is not the same as luminance.
Luminance (L or Y) is a linear measure of light.
L* (*Lstar) is perceptual lightness, it follows human perception (more or less, depending on a bazillion contextual things).
rgb2grey
rgb2grey does not convert to L*a*b*
Also, unfortunately some of the MATLAB functions for colorspaces have errors in implementation.
If you want to convert an sRGB color/image/pixel to LAB, then you need to follow this flowchart:
sRGB -> linear RGB -> CIEXYZ -> CIELAB
If you only want the greyscale or lightness information, with no color you can:
sRGB -> linear RGB -> CIE Y (spectral weighting) -> L* (perceptual lightness)
I discuss this simple method of sRGB to L* in this post
And if you want to see more in depth details, I suggest Bruce Lindbloom.

Related

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.

What range are L*a*b* values restricted to for a given reference white point?

I've got some images I want to do things in CIE L*a*b* with. What range can I expect the values to be in, given the initial sRGB values are in the range [0,1]?
I get my images like the following:
im_rgb = im2double(imread('/my/file/path/image.jpg'));
% ...do some muddling about with im_rgb, keeping range [0,1]
xform = makecform('srgb2lab');
im_lab = applycform(im_rgb, xform);
For starters, I'm reasonably sure that L* will be 0-100. However, I found this thread, which notes that "... a* and b* are not restricted to lie in the range [-100,100]."
Edit:
Matlab's default whitepoint is evaulated by whitepoint('ICC'), which returns 0.9642, 1, 0.8249. I'm using this value, as I'm not sure what else to use.
As I'm always using the same (default) transformation and the input colors are always real colors (as [0,1] for each of R, G, and B), Their equivalent L*a*b* representations are also real colors. Will these L*a*b* values also be bounded? If so, what are they bounded by, or how can I determine the boundaries?
You are basically asking how to find the boundary of the sRGB space in LAB, right?
So starting with L*, yes it will be bound between 0 and 100. This is by definition. If you look at the formula for conversion from XYZ to LAB you'll see that L = 116*(Y/Ywhitepoint)-16. When you are at sRGB white that Y ratio turns to 1 which makes the equation 116-16 = 100. A similar thing happens as back where the formula basically collapses to 4/29 * 116 -16 = 0.
Things are a little more complicated with the a and b. Since the XYZ -> LAB conversion is not linear the conversion doesn't make a easily described shape. But the outer surface of the sRGB cube will be become the outer boundary of the LAB space. What this means is you can take the extremes such as blue primary sRGB[0, 0, 1], convert to LAB and find what should be the furthest extent on the b axis: approximately -108. When you do that for all the corners of the sRGB cube you'll have a good idea about the extent of the sRGB space in LAB.
Most applications (notably Photoshop), clamp the encoding of the a and b channels between -128 and 127. This works fine in practice, but some large RGB spaces like ProPhoto RGB actually extent beyond this. Generally this doesn't have much practical consequence because most of these colors are imaginary, i.e. they sit outside the spectral locus.

Manually turn RGB image into Grayscale Matlab

Let me preface this by saying, I understand there are functions that would do this for me, but I wanted to do it manually so I could understand what exactly is happening here.
So my goal is to read in a RGB image and turn it into a grayscale. All of my image processing work up to this point has been solely grayscale based, so I am a little bit lost.
I have tried to first read in the image by doing
fid = fopen('color.raw');
myimage = imread(fid, [512 384], 'uint8');
fclose(fid);
but myimage ends up as an empty 0 x 0 matrix. I think I need to assign an "R" "G" and "B" value to each pixel, thus giving each pixel three values for the three colors, but I am not sure if thats correct, and even how to attempt that.
my question is the following: How would I read in a RGB image and then turn into a grayscale one.
EDIT: So I understand how I would go about turning the RGB into the grayscale after getting the R G and B values, but I cannot seem to make Matlab read in the image, can anyone offer any assistance? using imread seems to make the most sense, but
[pathname] = ...
uigetfile({'*.raw';'*.mdl';'*.mat';'*.*'},'File Selector');
fid = fopen(pathname);
myimage = imread(fid);
fclose(fid);
Is not working, im getting an error of invalid filename for fopen, and I really do not understand why.
Conceptually you just average the red, green, and blue components and then providing that average as the output for the red, green, and blue components. You can do this using a simple arithmetic mean
(r+g+b)/3.
Or for kicks, you can use a geometric mean to get a slightly different contrast..
(r*g*b)^(1/3).
imread - read image from graphics file (it's in the documentation)
http://www.mathworks.com/help/matlab/ref/imread.html
For RGB to gray scale use the luminosity method. http://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/
The luminosity method is a more sophisticated version of the average
method. It also averages the values, but it forms a weighted average
to account for human perception. We’re more sensitive to green than
other colors, so green is weighted most heavily. The formula for
luminosity is 0.21 R + 0.71 G + 0.07 B.
The problem with averaging all 3 values as other users have indicated is that that is not how our eyes work at all.
When you average your images, you get the result below (on the built in peppers.png image)
You are effectively doing grayImg=.33*R+.33*G+.33*B when you find the average, now compare that to how MATLAB calculates grayscale values (with consideration into how humans view images)
0.2989 * R + 0.5870 * G + 0.1140 * B
See the stark contrast in values?
To get better looking data, stay closer to the coefficients MATLAB uses :)
The way MATLAB renders it is like this:

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........