How to save image while keeping dimensions and pixels same? - matlab

I have to save the image. But when I try and keep the dimensions same, pixel values change. Is there any way to keep both intact.
C=imread('download.jpg');
C=rgb2gray(C);
%convert to DCT
[r1 c1]=size(C);
CDCT=floor(dct2(C));
dct=floor(dct2(C));
[r c]= size(dCipherText);
bye=c; %lenght of message bits
for i=r1:r1
for j=c1:-1:c1-28
.....%some operation on CDCT
end
end
imshow(idct2(CDCT),[0 255])
i=idct2(CDCT);
set(gcf,'PaperUnits','inches','PaperPosition',[0 0 c1 r1])
print -djpeg fa.jpg -r1
end

Don't use print to save the picture.
Use:
imwrite(i,'downdload_dct.jpg')
print will use the paper dimensions etc defined on your figure, rather than the image data itself. imwrite uses the data in i. You don't need imshow if you just want to re-save the image.
--
Update - sorry I see now that when you mean 'scaling', you don't mean the scaling of the picture but of the pixel values, and converting back from scalars to a colour. imshow only "scales" things on the screen, not in your actual data. So you will need to do that manually / numerically. Something like this would work, assuming i is real.
% ensure i ranges from 1 to 255
i = 1 + 254*(i-min(i(:))*(max(i(:))-min(i(:))) ;
% convert indices to RGB colour values (m x n x 3 array)
i = ind2rgb(i,jet(256));
not tested!

Related

2D convolution in Matlab/Octave

I = imread ("lena.jpg");
%imshow(I);
K = I;
C = conv2(I, K);
imshow(C);
I am expecting something like the following as indicated in this link.
But, my octave output is blank:
What could be the possible reason?
And, how can I obtain the expected output?
imshow() expect values between [0-255]. After your convolution all your value are way above 255. So of course when you use imshow(C), matlab/octave do a type conversion using uint8(). All your value equal 255 and the result is a white image. (0 = black, 255 = white).
You also should take into account severals things:
add the option 'same' to your convolution to preserve the original size of your image: conv2(I,K,'same')
If you only apply the convolution like that, you will obtain a strong border effect, because the central values of your image will be multiplied more time than the values in the border of your image. You should add a compensation matrix:
border_compensation = conv2(ones(size(K)),ones(size(K)),'same')
C = conv2(I,K,'same')./border_compensation
Normalize the final result (Don't take into account the point 2. if you really want the kind of output that you pointed out in your question)
C = uint8(C/max(C(:))*255)

Wrong output for 2d convolution function

As the title says, the output I’m getting out of this function is incorrect. By incorrect I mean that the data are overflowing. How do I normalise the matrix correctly? Currently almost all of the pictures I get are white.
I called the function from another MATLAB file like this:
mask = [3,10,3;0,0,0;-3,-10,-3];
A = imread(“football.jpg”);
B = ConvFun(A,mask);
function [ image ] = ConvFun( img,matrix )
[rows,cols] = size(img); %// Change
%// New - Create a padded matrix that is the same class as the input
new_img = zeros(rows+2,cols+2);
new_img = cast(new_img, class(img));
%// New - Place original image in padded result
new_img(2:end-1,2:end-1) = img;
%// Also create new output image the same size as the padded result
image = zeros(size(new_img));
image = cast(image, class(img));
for i=2:1:rows+1 %// Change
for j=2:1:cols+1 %// Change
value=0;
for g=-1:1:1
for l=-1:1:1
value=value+new_img(i+g,j+l)*matrix(g+2,l+2); %// Change
end
end
image(i,j)=value;
end
end
%// Change
%// Crop the image and remove the extra border pixels
image = image(2:end-1,2:end-1);
imshow(image)
end
In a convolution, if you want the pixel value to stay in the same range
, you need to make the mask add up to 1. Just divide the mask by sum(mask(:)) after defining it. This is however, not the case you are dealing with.
Sometimes that is not the needed. For example if you are doing edge detection (like the kernel you show), you don't really care about maintaining the pixel values. In those cases, the plotting of unnormalized images is more the problem. You can always set the imshow function to auto select display range: imshow(image,[]).
Also, I hope this is homework, as this is the absolutely worst way to code convolution. FFT based convolution is about 100 times faster generally, and MATLAB has an inbuilt for it.

Why I got wrong outputs for converting RGB to l*a*b* color values using MATLAB?

I have an image with green background and some shadows around my materials(some pieces of pumpkin). I want to remove background and shadows and then convert RGB color to lab* and separate l*, a*, b*. finally get mean of l*,a*,b* values.these are my codes:
I=imread('006.jpg'); %import image
I=double(I)./255; %convert to double
I=imresize(I,0.25); %resize image
G=I(:,:,2)-I(:,:,1)-I(:,:,3); %how green(2) compared to red(1) and blue(3)
L=I.*repmat(G < 0,[1,1,3]); %remove all values that are green
%convert rgb to lab
L=makecform('srgb2lab');
lab=applycform(I,L);
%separate l, a, b values
l=lab(:,:,1);
a=lab(:,:,2);
b=lab(:,:,3);
%calculate mean values
lm=mean(mean(l));
am=mean(mean(a));
bm=mean(mean(b));
At the end, these codes give me l=82, a=-31, b=78.
but they are wrong, because I check the range of these values with digital color meter and they should be approximately like l=70 , a=17, b=66. I think these codes show the lab values of background that I've removed instead of the lab values of materials!!!!
What can I do?
If you have MATLAB > R2014b, use rgb2lab instead of makecform and applycform, as per makecform doc itself :
lab = rgb2lab(L);
that may solve your problem as I think you did not apply the transformation to the right image. The image with no green (L) is not used as L is used to store the transformation data on the next line. The transformation is then applied to I and not L as it no longer exists.
That being said, your code computes the mean values on the entire image, not only the materials part as the background is blacked and not removed. If you want the mean values of the materials only, you may do the following :
I=imread('006.jpg'); %import image
I=double(I)./255; %convert to double
I=imresize(I,0.25); %resize image
%convert rgb to lab
lab=rgb2lab(I);
%separate l, a, b values
l=lab(:,:,1);
a=lab(:,:,2);
b=lab(:,:,3);
%calculate mean values
G=I(:,:2)-I(:,:,1)-I(:,:,3); %how green(2) compared to red(1) and blue(3)
I_materials = G < 0; % is materials 0/1
lm=mean(l(I_materials));
am=mean(a(I_materials));
bm=mean(b(I_materials));

Matlab: trouble with taking derivative of image?

So I need to take the derivative of an image in the x-direction for this assignment, with the goal of getting some form of gradient. My thought is to use the diff(command) on each row of the image and then apply a Gaussian filter. I haven't started the second part because the first is giving me trouble. In attempting to get the x-derivative I have:
origImage = imread('TightRope.png');
for h = 1:3 %%h represents color channel
for i = size(origImage,1)
newImage(i,:,h) = diff(origImage(i,:,h)); %%take derivative of row and translate to new row
end
end
The issue is somewhere along the way I get the error 'Subscripted assignment dimension mismatch.'.
Error in Untitled2 (line 14)
newImage(i,:,h) = diff(origImage(i,:,h));
Does anyone have any ideas on why that might be happening and if my approach is correct for getting the gradient/gaussian derivative?
Why not use fspecial along with imfilter instead?
figure;
I = imread('cameraman.tif');
subplot 131; imshow(I); title('original')
h = fspecial('prewitt');
derivative = imfilter(I,h','replicate'); %'
subplot 132; imshow(derivative); title('derivative')
hsize = 5;
sigma = 1;
h = fspecial('gaussian', hsize, sigma) ;
gaussian = imfilter(derivative,h','replicate'); %'
subplot 133; imshow(gaussian); title('derivative + gaussian')
The result is the following one:
If your goal is to use diff to generate the derivative rather than to create a loop, you can just tell diff to give you the derivative in the x-direction (along dimension 2):
newImage = diff(double(origImage), 1, 2);
The 1 is for the first derivative and 2 is for the derivative along the second dimension. See diff.
As #rayryeng mentions in his answer, it's important to cast the image as double.
Given a N element vector, diff returns a N-1 length vector, so the reason why you are getting an alignment mismatch is because you are trying to assign the output of diff into an incorrect number of slots. Concretely, supposing that N is the total number of columns, you are using diff on a 1 X N vector which thus returns a 1 x (N - 1) vector and you are trying to assign this output as a single row into the output image which is expected to be 1 x N. The missing element is causing the alignment mismatch. diff works by taking pairs of elements in the vector and subtracting them to produce new elements, thus the reason why there is one element missing in the final output.
If you want to get your code working, one way is to pad each row of the image or signal vector with an additional zero (for example) as input into diff. Something like this could work. Take note that I'll be converting your image to double to allow the derivative to take on negative values:
origImage = imread('...'); %// Place path to image here and read in
origImage = im2double(origImage); %// Change - Convert to double precision
newImage = zeros(size(origImage)); %// Change - Create blank new image and populate each row per channel manually
for h = 1:3 %%h represents color channel
for ii = 1:size(origImage,1) %// Change - fixed for loop iteration
newImage(ii,:,h) = diff([0 origImage(ii,:,h)]); %// Change
end
end
Take note that your for loop was incorrect since it didn't go over every row... just the last row.
When I use the onion.png image that's part of the image processing toolbox:
...and when I run this code, I get this image using imshow(newImage,[]);:
Take note that the difference filter was applied to each channel individually and I changed the intensities per channel so that the smallest value gets mapped to 0 and the largest value gets mapped to 1. How you can interpret this image is that any areasthat have a non-black colour have some non-zero differences and hence there is some activity going on in those areas and any areas that have a dark / black colour means that there is no activity going on in those areas. Take note that we applied a horizontal filter, so if you wanted to do this vertically, you'd simply repeat the behaviour but apply this column-wise instead of row-wise as you did above.

Using SVD to compress an image in MATLAB

I am brand new to MATLAB but am trying to do some image compression code for grayscale images.
Questions
How can I use SVD to trim off low-valued eigenvalues to reconstruct a compressed image?
Work/Attempts so far
My code so far is:
B=imread('images1.jpeg');
B=rgb2gray(B);
doubleB=double(B);
%read the image and store it as matrix B, convert the image to a grayscale
photo and convert the matrix to a class 'double' for values 0-255
[U,S,V]=svd(doubleB);
This allows me to successfully decompose the image matrix with eigenvalues stored in variable S.
How do I truncate S (which is 167x301, class double)? Let's say of the 167 eigenvalues I want to take only the top 100 (or any n really), how do I do that and reconstruct the compressed image?
Updated code/thoughts
Instead of putting a bunch of code in the comments section, this is the current draft I have. I have been able to successfully create the compressed image by manually changing N, but I would like to do 2 additional things:
1- Show a pannel of images for various compressions (i/e, run a loop for N = 5,10,25, etc.)
2- Somehow calculate the difference (error) between each image and the original and graph it.
I am horrible with understanding loops and output, but this is what I have tried:
B=imread('images1.jpeg');
B=rgb2gray(B);
doubleB=im2double(B);%
%read the image and store it as matrix B, convert the image to a grayscale
%photo and convert the image to a class 'double'
[U,S,V]=svd(doubleB);
C=S;
for N=[5,10,25,50,100]
C(N+1:end,:)=0;
C(:,N+1:end)=0;
D=U*C*V';
%Use singular value decomposition on the image doubleB, create a new matrix
%C (for Compression diagonal) and zero out all entries above N, (which in
%this case is 100). Then construct a new image, D, by using the new
%diagonal matrix C.
imshow(D);
error=C-D;
end
Obviously there are some errors because I don't get multiple pictures or know how to "graph" the error matrix
Although this question is old, it has helped me a lot to understand SVD. I have modified the code you have written in your question to make it work.
I believe you might have solved the problem, however just for the future reference for anyone visiting this page, I am including the complete code here with the output images and graph.
Below is the code:
close all
clear all
clc
%reading and converting the image
inImage=imread('fruits.jpg');
inImage=rgb2gray(inImage);
inImageD=double(inImage);
% decomposing the image using singular value decomposition
[U,S,V]=svd(inImageD);
% Using different number of singular values (diagonal of S) to compress and
% reconstruct the image
dispEr = [];
numSVals = [];
for N=5:25:300
% store the singular values in a temporary var
C = S;
% discard the diagonal values not required for compression
C(N+1:end,:)=0;
C(:,N+1:end)=0;
% Construct an Image using the selected singular values
D=U*C*V';
% display and compute error
figure;
buffer = sprintf('Image output using %d singular values', N)
imshow(uint8(D));
title(buffer);
error=sum(sum((inImageD-D).^2));
% store vals for display
dispEr = [dispEr; error];
numSVals = [numSVals; N];
end
% dislay the error graph
figure;
title('Error in compression');
plot(numSVals, dispEr);
grid on
xlabel('Number of Singular Values used');
ylabel('Error between compress and original image');
Applying this to the following image:
Gives the following result with only first 5 Singular Values,
with first 30 Singular Values,
and the first 55 Singular Values,
The change in error with increasing number of singular values can be seen in the graph below.
Here you can notice the graph is showing that using approximately 200 first singular values yields to approximately zero error.
Just to start, I assume you're aware that the SVD is really not the best tool to decorrelate the pixels in a single image. But it is good practice.
OK, so we know that B = U*S*V'. And we know S is diagonal, and sorted by magnitude. So by using only the top few values of S, you'll get an approximation of your image. Let's say C=U*S2*V', where S2 is your modified S. The sizes of U and V haven't changed, so the easiest thing to do for now is to zero the elements of S that you don't want to use, and run the reconstruction. (Easiest way to do this: S2=S; S2(N+1:end, :) = 0; S2(:, N+1:end) = 0;).
Now for the compression part. U is full, and so is V, so no matter what happens to S2, your data volume doesn't change. But look at what happens to U*S2. (Plot the image). If you kept N singular values in S2, then only the first N rows of S2 are nonzero. Compression! Except you still have to deal with V. You can't use the same trick after you've already done (U*S2), since more of U*S2 is nonzero than S2 was by itself. How can we use S2 on both sides? Well, it's diagonal, so use D=sqrt(S2), and now C=U*D*D*V'. So now U*D has only N nonzero rows, and D*V' has only N nonzero columns. Transmit only those quantities, and you can reconstruct C, which is approximately like B.
For example, here's a 512 x 512 B&W image of Lena:
We compute the SVD of Lena. Choosing the singular values above 1% of the maximum singular value, we are left with just 53 singular values. Reconstructing Lena with these singular values and the corresponding (left and right) singular vectors, we obtain a low-rank approximation of Lena:
Instead of storing 512 * 512 = 262144 values (each taking 8 bits), we can store 2 x (512 x 53) + 53 = 54325 values, which is approximately 20% of the original size. This is one example of how SVD can be used to do lossy image compression.
Here's the MATLAB code:
% open Lena image and convert from uint8 to double
Lena = double(imread('LenaBW.bmp'));
% perform SVD on Lena
[U,S,V] = svd(Lena);
% extract singular values
singvals = diag(S);
% find out where to truncate the U, S, V matrices
indices = find(singvals >= 0.01 * singvals(1));
% reduce SVD matrices
U_red = U(:,indices);
S_red = S(indices,indices);
V_red = V(:,indices);
% construct low-rank approximation of Lena
Lena_red = U_red * S_red * V_red';
% print results to command window
r = num2str(length(indices));
m = num2str(length(singvals));
disp(['Low-rank approximation used ',r,' of ',m,' singular values']);
% save reduced Lena
imwrite(uint8(Lena_red),'Reduced Lena.bmp');
taking the first n max number of eigenvalues and their corresponding eigenvectors may solve your problem.For PCA, the original data multiplied by the first ascending eigenvectors will construct your image by n x d where d represents the number of eigenvectors.