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

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.

Related

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.

Reading grayscale image in matlab [duplicate]

This question already has an answer here:
What does the index refer to when selecting a pixel on an image in Matlab?
(1 answer)
Closed 6 years ago.
I have gray scale image "lena.bmp". I want read this image in matlab using imread() function.
When i use code below to read and show image my image is dark (black).
img = imread('lena.bmp');
imshow(img);
But when i use code below, I have no problem to view.
[img map]= imread('lena.bmp');
imshow(img,map);
It seems that my first code doses not reading image in grayscale mode (like what rgb2gray function generate).
My image is as follows:
What can i do to solve this problem?
Your image is an "indexed" image. That means it contains integer values which act as "labels" more than anything, and each of those labels is mapped to a colour (i.e. an rgb triplet). Your map variable represents that mapping; at row 5 you have the rgb triplet that corresponds to 'label' "5", for instance.
To see what I mean, do unique(img) and you'll see that the values of your img array are in fact quite regular. The command rgbplot can demonstrate the actual colourmap graphically. Run rgbplot(map) on your map variable to see the mapping for each of the red green and blue colours.
Now, save and read the image below on your computer as img2 and compare the array values.
This image was generated by converting from the "indexed" image you linked to, to a "grayscale" one using photoediting software (the GIMP). The difference is that
in a grayscale image, the pixel values represent actual intensities, rather than integer 'labels'. Imread reads grayscale images as uint8 images by default, meaning it assigns intensity values to pixels ranging from 0 (black) to 255 (white). Since these values happen to be integers you could still cheat and treat them as 'labels' and force a colour-mapping on them. But if you assign a 'linear map' (i.e. value 1 = intensity 1, value 2 = intensity 2, etc) then your image will look as you would expect.
You'll see that the values from unique(img2) are quite different. If you imshow(img2) you'll see this displays as you'd expect. If you don't specify a colormap for imshow, it will assume that the map is a linear mapping from the lowest to the highest value in the image array, which explains why your indexed image looked weird, since its values were never supposed to correspond to intensities.
Also try imagesc(img2) which will show this but using the "current" colormap. imagesc causes the colormap to be "scaled", so that the lowest colour goes to the lowest value in the image, and similarly for the highest.
The default colormap is jet so you should see a psychedelic looking image but you should be able to make out lena clearly. If you try colormap gray you should see the gray version again. Also try colormap hot. Now to make sense of the colormaps, try the rgbplot command on them (e.g. rgbplot(gray), rgbplot(hot) etc).
So, going back to imshow, imshow basically allows you to display an indexed image, and specify what colormap you want to use to display it. If you don't specify the colormap, it will just use a linear interpolation from the lowest value to the highest as your map. Therefore imshow(img) will show the image pretty much in the same way as imagesc(img) with a gray colormap. And since the values in your first img represent evenly spaced 'labels' rather than actual intensities, you'll get a rubbish picture out.
EDIT: If you want to convert your indexed image to a grayscale image, matlab provides the ind2gray function, e.g.:
[img, map] = imread('lena.bmp');
img_gray = ind2gray(img, map);
This is probably what you need if you mean to process pixel values as intensities.

Access RGB channels in an image in MATLAB

I want to access the red channel of each pixel in my image. I don't want to change it. I just want to identify the pixels with a range of red. I'm looking for pixels that will have the colors like RGB(15,0,0), RGB(120,0,0), RGB(200,0,0) and so on. My image is mostly gray, I want to identify the red boxes on that.
I tried:
image = imread('myimage.jpg');
figure; imshow(image);
redPlane = image(:,:,1);
figure; imshow(redPlane);
The second figure displayed is all gray. It took off the red.
You are visualizing the red channel as a grayscale image. Think about it. The image is essentially a 3D matrix. By doing image(:,:,1);, you are accessing the first slice of that image, which is a 2D matrix and this corresponds to the red components of each pixel. imshow functions such that if the input is a 2D matrix, then the output is automatically visualized as grayscale. If imshow is a 3D matrix, then the output is automatically visualized in colour, where the first, second and third slices of the matrix correspond to the red, green and blue components respectively.
Therefore, by doing imshow on this 2D matrix, it would obviously be grayscale. You're just interpreting the results incorrectly. Here, the whiter the pixel the more red the pixel is in that location of the image. For example, assuming your image is uint8 (unsigned 8-bit integer) if a value has 255 at a particular location, this means that the pixel has a fully red component whereas if you had a value of 0 at a particular location, this means that there is no red component. This would be visualized in black and white.
If you want to display how red a pixel is, then put this into a 3D matrix where the second (green) and third (blue) channels are all zero, while you set the red channel to be from the first slice of your original image. In other words, try this:
imageRed = uint8(zeros(size(image))); %// Create blank image
imageRed(:,:,1) = redPlane; %// Set red channel accordingly
imshow(imageRed); %// Show this image
However, if you just want to process the red channel, then there's no need to visualize it. Just use it straight out of the matrix itself. You said you wanted to look for specific red channel values in your image. Ignoring the green and blue components, you can do something like this. Let's say we want to create an output Boolean map locationMap such that any location that is true / 1 will mean that this is a location has a red value you're looking for, and false / 0 means that it isn't. As such, do something like:
redPlane = image(:,:,1);
% // Place values of red you want to check here
redValuesToCheck = [15 20 100];
%// Initialize a boolean map where true
%// means this is a red value we're looking for and
%// false otherwise
locationMap = false(size(redPlane));
%// For each red value we want to check...
for val = redValuesToCheck
%// Find those locations that share this
%// value, and set to true on the boolean map
locationMap(redPlane == val) = true;
end
%// Show the map
imshow(locationMap);
One small subtlety here that you may or may not notice, but I'll bring it up anyway. locationMap is a Boolean variable, and when you use imshow on this, true gets visualized to white while false gets visualized to black.
Minor note
Using image as a variable name is a very bad idea. image is a pre-defined function already included in MATLAB that takes in a matrix of numbers and visualizes it in a figure. You should use something else instead, as you may have other functions that rely on this function but you won't be able to run them as the functions are expecting the function image, but you have shadowed it over with a variable instead.

How to get the red image from gray image in matlab

i have an image let say a=imread('example.bmp'i got all three channel from it :
R=a(:,:,1);
G=a(:,:,2);
B=a(:,:,3);
and i have the gray image of it:
igray=rgb2gray(a);
Can I get the red component from the gray image ?
No, you can't, since igray will be a two dimensional image (a is three dimensional, with the third dimension being colors planes), containing only intensity values for each pixel.
To convert an RGB image to grayscale, rbg2gray uses a formula you can find here
As you can see, it's a 3 variables equation, therefore you can't find them using intensity value alone.
The rgb2gray function effectively does this to every RGB pixel (type edit rgb2gray):
Gray = 0.298936021293776*Red+0.587043074451121*Green+0.114020904255103*Blue;
If you only have Gray in the equation above then you have one equation with three unknowns. More information is needed to solve for Red.
If you just want an RGB image where every channel has the same components, i.e., those created by rgb2gray, then use
igray(:,:,3) = rgb2gray(a); % Set last component first to fully allocate array
igray(:,:,1) = igray(:,:,3);
igray(:,:,2) = igray(:,:,3);
Or an RGB image where all the channels are equivalent to the red channel:
igray(:,:,3) = a(:,:,1);
igray(:,:,1) = a(:,:,1);
igray(:,:,2) = a(:,:,1);
The repmat function can be used as well if you prefer.
While nothing in horchler's very long answer is incorrect, I think you just want to get the red channel from the rgb image which is very easy.
A=imread('colorImg.jpg')
redChannel=A(:,:,1)
That's it!
That will return a matrix of type uint8, to convert to double, just do double(redChannel) and you can multipy/divide it by 255 as necessary.

An explanation for this MATLAB code snippet

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