MATLAB does not show the correct calculation - matlab

I'm trying to do a simple algorithm on an image but i figured out there is a problem, here is a piece of my code:
I = imread('C:/test.bmp' ,'bmp');
z = I(1, 1, 1);
c = I(1, 1, 2);
b = I(1, 1, 3);
v = z+c+b
this piece of code should print the sum of R,G and B values of the first pixel. when In print each R,G and B individually, there are 123, 43, 140. but the value of v(sum) is always equal to 255! I tried it with different pics, but I get the same result!
I have no idea why is this happening, happy to get help.

Depending on the colour depth and file format, imread outputs different data types. In this case it was a uint8 with a maximum of 255. The sum of unit8 variables is also a uint8.
The easiest way to deal with it is using im2double while loading the images. Every colour channel is scaled to a double value in the [0,1] interval.
I = im2double(imread('C:/test.bmp' ,'bmp'));

Related

Quantizing an image in matlab

So I'm trying to figure out why my code doesn't seem to be displaying the properly uniformed quantized image into 4 levels.
Q1 =uint8(zeros(ROWS, COLS, CHANNELS));
for band = 1 : CHANNELS,
for x = 1 : ROWS,
for y = 1 : COLS,
Q1(ROWS,COLS,CHANNELS) = uint8(double(I1(ROWS,COLS,CHANNELS) / 2^4)*2^4);
end
end
end
No5 = figure;
imshow(Q1);
title('Part D: K = 4');
It is because you are not quantifying. You divide a double by 16, then multiply again by 16, then convert it to uint8. The right way to quantize is to divide by 16, throw away any decimals, then multiply by 16:
Q1 = uint8(floor(I1 / 16) * 16);
In the code snippet above, I assume I1 is a double. Convert it to double if its not: I1=double(I1).
Note that you don't need the loops, MATLAB will apply the operation to each element in the matrix.
Note also that if I1 is an integer type, you can do something like this:
Q1 = (uint8(I1) / 16) * 16;
but this is actually equivalent to replacing the floor by round in the first example. This means you get an uneven distribution of values: 0-7 are mapped to 0, 8-23 are mapped to 16, etc. and 248-255 are all mapped to 255 (not a multiple of 16!). That is, 8 numbers are mapped to 0, and 8 are mapped to 255, instead of mapping 16 numbers to each possible multiple of 16 as the floor code does.
The 16 in the code above means that there will be 256/16=16 different grey levels in the output. If you want a different number, say n, use 256/n instead of 16.
It's because you are using ROWS, COLS, CHANNELS as your index, it should be x,y,band. Also, the final multiplication of 2^4 has be after the uint8 cast otherwise no rounding ever takes place.
In practice you should avoid the for loops in Matlab since matrix operations are much faster. Replace your code with
Q1=uint8(double(I1/2^4))*2^4
No5 = figure;
imshow(Q1);
title('Part D: K = 4');

Address Complex numbers and create new matrix in MATLAB

I have a complex matrix of size 3x2x372 complex double. I would like to work with only one specific of these three dimensions. Therefore, I used the following code to make the table easier to read:
new_output = abs(output);
In fact, the new matrix is of size 3x2x372 double. I guess it makes the further computation simpler. So I obtain the following output:
I would now like to create a matrix that only refers to the highlighted values. So it should ideally be of size 2x372 double.
Make a for-loop and assign the last row to a new matrix.
mat = zeroes(372, 2)
for k = 1:372
a = val(:, :, k)
mat(k, :) = a(1, :)
end
Edit: above gives you a 372x2 matrix. Use below to get a 2x372 matrix
mat = zeroes(2, 372)
And
mat(:, k) = a(1,:).'
in the loop
Actually, you need the last row from each "slice", so you can get it by:
new_output=data(size(data,1),:,:);
But that will give you the same dimensions as the original matrix, with 3D. To directly get it as 2D matrix, use squeeze:
new_output=squeeze(data(size(data,1),:,:));

RGB to YIQ conversion

I wrote code for rgb to yiq conversion.I get results but i don't know if this is correct.
%extract the red green blue elements
ImageGridRed = double(ImageRGB(:,:,1))';
ImageGridGreen = double(ImageRGB(:,:,2))';
ImageGridBlue = double(ImageRGB(:,:,3))';
%make the 300x300 matrices into 1x90000 matrices
flag = 1;
for i =1:1:300
for j = 1:1:300
imageGR(flag) = ImageGridRed(j,i);
imageGG(flag) = ImageGridGreen(j,i);
imageGB(flag) = ImageGridBlue(j,i);
flag = flag+1;
end
end
%put the 3 matrices into 1 matrix 90000x3
for j=1:1:300*300
colorRGB(j,1) = imageGR(j);
colorRGB(j,2) = imageGG(j);
colorRGB(j,3) = imageGB(j);
end
YIQ = rgb2ntsc([colorRGB(:,1) colorRGB(:,2) colorRGB(:,3)]);
I wrote this because the rgb2ntsc function needs mx3 matrix for input.I use the number 300 beacuse the picture is 300x300 pixels.I am going to seperate the picture in blocks in my project so dont give attention to the 300 number because i am going to change that, i put it just as an example.
thank you.
What you're doing is completely unnecessary. If you consult the documentation on rgb2ntsc, it also accepts a RGB image. Therefore, when you put in a RGB image, the output will be a 3 channel image, where the first channel is the luminance, or Y component and the second and third channels are the hue and saturation information (I and Q respectively). You don't need to decompose the image into a M x 3 matrix.
Therefore, simply do:
YIQ = rgb2ntsc(ImageRGB);
Make sure that ImageRGB is a RGB image where the first channel is red, second is green and third is blue.
Edit
With your comments, you want to take all of the pixels and place it into a M x 3 matrix where M is the total number of pixels. You would use this as input into rgb2ntsc. The function accepts a M x 3 matrix of RGB values where each row is a RGB tuple. The output in this case will be another M x 3 matrix where each row is its YIQ counterpart. Your code does do what you want it to do, but I would recommend that you do away with the for loops and replace it with:
colorRGB = reshape(permute(ImageRGB, [3 1 2]), 3, []).';,
After, do YIQ = rgb2ntsc(colorRGB);. colorRGB will already be a M x 3 matrix, so that column indexing you're doing is superfluous.
With the above using reshape and permute, it's very unnecessary to use the loops. In fact, I would argue that the for loop code is slower. Stick with the above code to get this done fast. Once you have your matrix in this fashion, then I suppose the code is doing what you want it to do.... however, I would personally just do a conversion on the image itself, then split it up into blocks or whatever you want to do after the fact.

How to use reshape in Matlab?

I want to reshape pixel intensity by imagesize*1(column vector).
Imvect = reshape(I,imsize,1);
But why these error comes?
Error using reshape
To RESHAPE the number of elements must not change.
Let's start with the syntax used in the documentation:
B = reshape(A,sz1,...,szN)
What reshape does is to take the matrix A, straightens it out, and gives it a new size, that's determined by the 2nd, 3rd to the Nth argument. For this to be possible, you need to have the same number of elements in the input matrix as you have in the output matrix. You can't make a 1x5 vector turn into a 2x3 vector, as one element would be missing. The number of elements in the output matrix will be proportional to the product of sz1, sz2, ..., szN. Now, if you know you want N rows, but don't know exactly how many columns you have, you might use the [] syntax, that tells MATLAB to use as many columns as necessary to make the number of elements be equal.
So reshape(A, 2, [], 3) will become a 2xNx3 matrix, where, for a matrix with 24 elements, N will be 4.
Now, in your case this is not the case. numel(I) ~= imsize. If mod(numel(I), imsize) ~= 0 then your imsize is definitely incorrect. However, if mod(numel(I), imsize) == 0, then your error might be that you want imsize number of rows, and a number of columns that makes this possible. If it's the latter, then this should work:
Imvect = reshape(I,imsize, []);
If you simply want to make you matrix I a vector of size (numel(I), 1), then you should use the colon operator :, as such:
Imvect = I(:);
An alternative, if you really want to use reshape, is to specify that you want a single column, and let MATLAB select the number of rows, as such:
Imvect = reshape(I, [], 1);

Split matrix into non-overlapping submatrices

I have an image of any size that I need to split into non-overlapping regions of 15x15 pixels. Previously I looked this up and used the following code:
newIm = rand(size(im2, 1),size(im2, 2));
subIm = mat2cell(newIm, 15*ones(size(newIm,1)/15,1), 15*ones(size(newIm,2)/15,1));
My problem is that I may not always be able to split the matrix into nice 15x15 regions. How can I fix this? Also, can you explain what exactly happens? I'd like to understand Matlab better for future use!
If you use the above code with a size not perfectly divisible by 15 (say 160), you will get the following error in MATLAB:
Input arguments, D1 through D2, must sum to each dimension of the input matrix size, [160 160].'
So you have to make your second and third input arguments of mat2cell sum to 160. Then you are done.
Code taken from here
blockSize=[15 15];
wholeBlockRows = floor(size(newIm,1)/ blockSize(1));
blockVectorR = [blockSize(1) * ones(1, wholeBlockRows), rem(size(newIm,1), blockSize(1))];
wholeBlockCols = floor(size(newIm,2)/ blockSize(2));
blockVectorC = [blockSize(2) * ones(1, wholeBlockCols), rem(size(newIm,2), blockSize(2))];
% sum of blockVectorR and blockVectorC will be equal to size(newIm,1) and
% size(newIm,2) respectively.
ca = mat2cell(newIm, blockVectorR, blockVectorC, size(newIm,3));
In your output cell array, you will see sub-images in the last row and column where either rows or columns (or both) are equal to: rem(size(newIm,1), blockSize(1)) or (and) rem(size(newIm,2), blockSize(2))