Matlab RGB Image to Gray Scale Manually - image

I have a RGB image and want to apply following formulas to it so I get another image. How can I do that? I know how to read/write image and I know how to loop and apply formulas but I don't know functions to extract number of rows and columns of image in a variable and image pixles values of 3 planes in 3-dimensional plane.
I = imread('myimage.jpg');
RGBImagePixles = [?, ?, ?] %of I
ROWS = ? %of I
COLUMNS = ? %of I
for r = 0 : ROWS
for c = 0 : COLUMNS
N[r, c] = RGBImagePixles[r,c,1] + RGBImagePixles[r,c,2] + RGBImagePixles[r,c,3]
end
end
figure, imshow(N);

The output of imread is a 3 dimensional array, actually 3 matrices stacked along the 3rd dimension - so if your image is m pixels high and n pixels wide, you'd get a m x n x 3 array.
so:
RGBImagePixles = I;
ROWS = size (I,1);
COLUMNS = size(I,2);
and you can replace the loop with:
N = sum(I, 3);
However, I am not sure that simple summation is what you need in order to produce a grayscale image.

[ROWS COLUMNS DIMS] = size(I);

I assume that RGB to grayscale is just an example, and your real goal is to learn how to manipulate the pixels of an image. Otherwise, you should just use:
ImageRGB = imread('yourfile.jpg')
ImageGray = rgb2gray(ImageRGB)
To do it by hand:
ImageRGB = imread('yourfile.jpg')
ImageGray = sum(ImageRGB,3) / (3*255)
You have to divide by 3*255 because matlab expects a grayscale image's values to be between 0 and 1, while the RGB values will between 0 and 255 in each channel.

Related

Why does downsample appear as a gray image?

In the implementation of downsampling by a factor of 2 to the image, the downsampled image is gray. What should I do in order to add all of the color components to the downsampling implementation so that it will be a color image?
I = imread('lena.gif','gif');
[j k] = size(I)
x_new = j./2;
y_new = k./2;
x_scale = j./x_new;
y_scale = k./y_new;
M = zeros(x_new,y_new);
for count1 = 1:x_new
for count2 = 1:y_new
M(count1,count2) = I(count1.*x_scale,count2.*y_scale);
end
end
figure,imshow(I);
title('Original Image');
M = uint8(M);
figure,imshow(M);
title('Downsample');
GIF images are what are known as indexed images. This means that what you read in with imread are values that are indices to a colour map. Each index generates a unique colour for you, and that's how GIF images are stored. They choose from a predefined set of colours, and each pixel in the GIF image comes from one of the colours in the colour map.
You first need to convert the image into RGB, and you do that with ind2rgb. However, you need to read in the colour map first with the two-output version of imread. You also will want to convert the images to uint8 as good practice with im2uint8:
[X,map] = imread('lena.gif');
I = im2uint8(ind2rgb(X,map));
What you need to do next is what #NKN suggested. You must apply the algorithm to all channels.
As such, simply make an output matrix that has three channels, and apply the algorithm to each plane independently. If I can make a suggestion, when accessing pixels this way after you downsample, make sure you floor or round the image coordinates so you're not inadvertently specifying locations that aren't defined - things like (13.8, 25.5) for example. Image pixel locations are integer, so you need to make sure the coordinates are integer too.
[X,map] = imread('lena.gif');
I = im2uint8(ind2rgb(X,map));
j = size(I,1); %// Change
k = size(I,2);
x_new = j./2;
y_new = k./2;
x_scale = j./x_new;
y_scale = k./y_new;
M = zeros(x_new,y_new,size(I,3)); %// Change
for jj = 1 : size(I,3) %// Change
for count1 = 1:x_new
for count2 = 1:y_new
M(count1,count2,jj) = I(floor(count1.*x_scale),floor(count2.*y_scale),jj); %// Change
end
end
end
figure,imshow(I);
title('Original Image');
M = uint8(M);
figure,imshow(M);
title('Downsample');
To test this, I'm using the mandrill dataset that's part of MATLAB. It is an indexed image with an associated colour map. These are coincidentally stored in X and map respectfully:
load mandrill;
I = im2uint8(ind2rgb(X,map));
Running the modified code, I get these two figures:
When you read the original image it contains 3 layers, R-G-B (as suggested by #rayryeng:
[X,map] = imread('lena.gif');
I = ind2rgb(X,map);
size(I)
ans =
768 1024 3
You should perform the down-sampling process on all the layers:
The code you provided does not down-sample. A simple downsampling example is as follows:
imshow(I(1:2:end,1:2:end,:))

How to draw repeating straight lines with specific radius and angle in matlab?

Suppose i would like to draw an image like the following:
Where the pixel values are refined to 0 for black and white for 1.
These line are drawn with specific radius and angles
Now I create a 80 x 160 matrix
texturematrix = zeros(80,160);
then i want to change particular elements to be 1 according to the lines conditions
but how do i make them repeatedly with specific distance apart from each others effectively?
Thanks a lot everyone!
This might not be what you are looking for, but generating such an image could be done by plotting a set of lines, as follows:
% grid sizes
m = 6;
n = 5;
% line length and angle
len = 1;
theta = .1*pi;
[a,b] = meshgrid(1:m,1:n);
x = reshape([a(:),a(:)+len*cos(theta),nan(numel(a),1)]',[],1);
y = reshape([b(:),b(:)+len*sin(theta),nan(numel(b),1)]',[],1);
h = figure();
plot(x,y,'k', 'LineWidth', 2);
But this has nothing to do with a texture matrix. So, we construct a matrix of desired size:
set(gca, 'position',[0 0 1 1], 'units','normalized', 'YTick',[], 'XTick',[]);
frame = frame2im(getframe(h),[0 0 1 1]);
im = imresize(frame,[80 160]);
M = ~(im(2:end,2:end,1)==255);

How to add a Gaussian shaped object to an image?

I am interested in adding a single Gaussian shaped object to an existing image, something like in the attached image. The base image that I would like to add the object to is 8-bit unsigned with values ranging from 0-255. The bright object in the attached image is actually a tree represented by normalized difference vegetation index (NDVI) data. The attached script is what I have have so far. How can I add a a Gaussian shaped abject (i.e. a tree) with values ranging from 110-155 to an existing NDVI image?
Sample data available here which can be used with this script to calculate NDVI
file = 'F:\path\to\fourband\image.tif';
[I R] = geotiffread(file);
outputdir = 'F:\path\to\output\directory\'
%% Make NDVI calculations
NIR = im2single(I(:,:,4));
red = im2single(I(:,:,1));
ndvi = (NIR - red) ./ (NIR + red);
ndvi = double(ndvi);
%% Stretch NDVI to 0-255 and convert to 8-bit unsigned integer
ndvi = floor((ndvi + 1) * 128); % [-1 1] -> [0 256]
ndvi(ndvi < 0) = 0; % not really necessary, just in case & for symmetry
ndvi(ndvi > 255) = 255; % in case the original value was exactly 1
ndvi = uint8(ndvi); % change data type from double to uint8
%% Need to add a random tree in the image here
%% Write to geotiff
tiffdata = geotiffinfo(file);
outfilename = [outputdir 'ndvi_' '.tif'];
geotiffwrite(outfilename, ndvi, R, 'GeoKeyDirectoryTag', tiffdata.GeoTIFFTags.GeoKeyDirectoryTag)
Your post is asking how to do three things:
How do we generate a Gaussian shaped object?
How can we do this so that the values range between 110 - 155?
How do we place this in our image?
Let's answer each one separately, where the order of each question builds on the knowledge from the previous questions.
How do we generate a Gaussian shaped object?
You can use fspecial from the Image Processing Toolbox to generate a Gaussian for you:
mask = fspecial('gaussian', hsize, sigma);
hsize specifies the size of your Gaussian. You have not specified it here in your question, so I'm assuming you will want to play around with this yourself. This will produce a hsize x hsize Gaussian matrix. sigma is the standard deviation of your Gaussian distribution. Again, you have also not specified what this is. sigma and hsize go hand-in-hand. Referring to my previous post on how to determine sigma, it is generally a good rule to set the standard deviation of your mask to be set to the 3-sigma rule. As such, once you set hsize, you can calculate sigma to be:
sigma = (hsize-1) / 6;
As such, figure out what hsize is, then calculate your sigma. After, invoke fspecial like I did above. It's generally a good idea to make hsize an odd integer. The reason why is because when we finally place this in your image, the syntax to do this will allow your mask to be symmetrically placed. I'll talk about this when we get to the last question.
How can we do this so that the values range between 110 - 155?
We can do this by adjusting the values within mask so that the minimum is 110 while the maximum is 155. This can be done by:
%// Adjust so that values are between 0 and 1
maskAdjust = (mask - min(mask(:))) / (max(mask(:)) - min(mask(:)));
%//Scale by 45 so the range goes between 0 and 45
%//Cast to uint8 to make this compatible for your image
maskAdjust = uint8(45*maskAdjust);
%// Add 110 to every value to range goes between 110 - 155
maskAdjust = maskAdjust + 110;
In general, if you want to adjust the values within your Gaussian mask so that it goes from [a,b], you would normalize between 0 and 1 first, then do:
maskAdjust = uint8((b-a)*maskAdjust) + a;
You'll notice that we cast this mask to uint8. The reason we do this is to make the mask compatible to be placed in your image.
How do we place this in our image?
All you have to do is figure out the row and column you would like the centre of the Gaussian mask to be placed. Let's assume these variables are stored in row and col. As such, assuming you want to place this in ndvi, all you have to do is the following:
hsizeHalf = floor(hsize/2); %// hsize being odd is important
%// Place Gaussian shape in our image
ndvi(row - hsizeHalf : row + hsizeHalf, col - hsizeHalf : col + hsizeHalf) = maskAdjust;
The reason why hsize should be odd is to allow an even placement of the shape in the image. For example, if the mask size is 5 x 5, then the above syntax for ndvi simplifies to:
ndvi(row-2:row+2, col-2:col+2) = maskAdjust;
From the centre of the mask, it stretches 2 rows above and 2 rows below. The columns stretch from 2 columns to the left to 2 columns to the right. If the mask size was even, then we would have an ambiguous choice on how we should place the mask. If the mask size was 4 x 4 as an example, should we choose the second row, or third row as the centre axis? As such, to simplify things, make sure that the size of your mask is odd, or mod(hsize,2) == 1.
This should hopefully and adequately answer your questions. Good luck!

drawn image, converted back

i want to draw image, do not know how to portray the image output kmeans
my code:
close all; clc; clear;
img = imread('pic7.png');
figure(), imshow(img);
impixelregion;
% nastavenie noveho obrazka
[y x z] = size(img)
for i=1:1:y
for j=1:1:x
imgNew(i, j, :) = 0;
end
end
[X_no_dither, map]= rgb2ind(img,8,'nodither');
figure, imshow(X_no_dither, map);
impixelregion;
m = im2double(X_no_dither)
idx = kmeans(m,4,'emptyaction','singleton');
how i draw image ?
Thanks.
In kmeans, the rows are the things we want to cluster (i.e. pixels by colour), the columns are the variables. Therefore, we cannot just pass in a image straight in, it has to be reshaped first. For example if we look at this MATLAB example., the image is first converted into lab colorspace (and is in lab_he).
First, they take only the a and b elements:
ab = double(lab_he(:,:,2:3));
Then, reshape so that ab is of size n x m where n = total number of pixels and m = 2 - this is because each pixel is being clustered based on both a and b values:
nrows = size(ab,1);
ncols = size(ab,2);
ab = reshape(ab,nrows*ncols,2);
Now, sort those pixels into three colors:
nColors = 3;
% repeat the clustering 3 times to avoid local minima
[cluster_idx cluster_center] = kmeans(ab,nColors,'distance','sqEuclidean', ...
'Replicates',3);
The result then has to be reshape'd back into an image to be displayed:
pixel_labels = reshape(cluster_idx,nrows,ncols);
imshow(pixel_labels,[]), title('image labeled by cluster index');
In your case, as you're using a indexed image, try something like this:
idx = kmeans(m(:),4,'emptyaction','singleton');
idx = reshape(idx,size(m));
imshow(idx, []);
m(:) just arranges the pixels as a single column. kmeans then sorts them into four clusters. Afterwards, we reshape the indexes back using the size of our input image, and then display with imshow as normal.
You should read the linked example closely and make sure you understand what they are doing and why.

K means clustering in MATLAB - output image

To perform K means clustering with k = 3 (segments). So I:
1) Converted the RGB img into grayscale
2) Casted the original image into a n X 1, column matrix
3) idx = kmeans(column_matrix)
4) output = idx, casted back into the same dimensions as the original image.
My questions are :
A
When I do imshow(output), I get a plain white image. However when I do imshow(output[0 5]), it shows the output image. I understand that 0 and 5 specify the display range. But why do I have to do this?
B)
Now the output image is meant to be split into 3 segments right. How do I threshold it such that I assign a
0 for the clusters of region 1
1 for clusters of region 2
2 for clusters of region 3
As the whole point of me doing this clustering is so that I can segment the image into 3 regions.
Many thanks.
Kind Regards.
A: Given that your matrix output contains scalar values ranging from 1 to 3, imshow(output) is treating this as a grayscale matrix and assuming that the full range of values is 0 to 255. This is why constraining the color limits is necessary as otherwise your image is all white or almost all white.
B: output = output - 1
As pointed out by Ryan, your problem is probably just how you display the image. Here's a working example:
snow = rand(256, 256);
figure;
imagesc(snow);
nClusters = 3;
clusterIndices = kmeans(snow(:), nClusters);
figure;
imagesc(reshape(clusterIndices, [256, 256]));

Resources