Downsampling an image issue - matlab

So I am trying to downsample an image using nested for loops. Here, i have a 359x479(widthxheight) image. I am trying to downsample it to a 180x240 image by removing the even rows and columns. Yet, it doesn't seem to be working. I end up getting the same image as the output.
a=imread('w.jpg'); %input image
a=im2double(a); %convert it to double
r=[[1 1 1];[1 1 1];[1 1 1]]/9; % the next 3 steps done to low pass
filter the image
c=imfilter(a,r,'replicate');
imshow(c);
for i=1:359 % for rows
for j=1:479 %for columns
if(mod(i,2)~=0) %to remove even rows
if(mod(j,2)~=0) %to remove odd columns
b(i,j)=c(i,j); %if i and j are odd, the pixel value is assigned to b
end
end
end
end
figure, imshow(b);
should get a 180x240 image but still getting the same image of size 359x479

You also need to assign only one pixel on two ! If you do not, half of yours columns/rows will contain only 0 value.
so you need to use:
b(ceil(i/2),ceil(j/2))=c(i,j);
where 2 correspond to the value of your modulo.
You could also avoid to use some loops by simply writing:
b = c(1:2:259,1:2:194);

Related

On 1x2 convolution and combining gradients

So I'm trying to understand convolution and the process on making gradients and I wanted to just see the horizontal gradient of the 1x2 operator on an image named I1. When I tried to use this code I only get a black screen so I'm trying to figure out what went wrong here,sans using conv of course. (I'm also going to try out Sobel too, so I'd like some tips on how to get that going.)
I1 = uint8(round(sum(C1,3)/3));
figure,imshow(I1);
Kern =[-1,1];
Omega = zeros([size(I1,1) size(I1,2)]);
for i=1:ROWS
for j=1:COLS
Work = double(I1(i,j)).*Kern;
Omega(i,j) = sum(Work(:));
end
end
figure,imshow(uint8(Omega));
The problem is that you're only using 1 pixel from I1 to multiply by your kernel. Since you're using one value, the end effect is:
a.*[-1 1]
which gives you
[-a a]
When you sum this, obviously you get zero. To fix this, you'll need to use the same number of pixels from I1 as you have elements in your kernel (in this case, 2). This will also mean that you need to adjust your loop indices:
for i=1:ROWS-1 % avoid accessing outside image
for j=1:COLS-1
Work = double(I1(i,j:j+1)).*Kern; % j:j+1 gives us 2 pixels
Omega(i,j) = sum(Work(:));
end
end
You can also condense the two lines inside the loop into one:
Kern = [-1;1]; % make Kern a column vector
...
for i=1:ROWS-1
for j=1:COLS-1
Omega(i,j) = double(I1(i,j:j+1))*Kern; % vector multiplication, not elementwise
end
end
Another thing you might want to try is use imagesc(Omega) instead of imshow. imagesc will scale the values of the image so it's more visible.

Random Sampling/Matlab/Matrix

I am trying to create a set of 320 matrices, each having dimensions 1152 x 241. Each matrix represents a different time step. I am trying to populate each cell, using a random value from another file. This other file is also dimensioned 1152 x 241, but there are ~2520 time steps from which to choose.
So what is supposed to happen is pick a cell, populate with a value from a random time step from the big file, and move onto the adjacent cell and do the same thing. Repeat until 320 matrices have been created.
Problem is I run the code and I only create one matrix. What do I need to do to fix my code so that 320 matrices are created? Thanks!
clear all;
clc;
% Load datafile
load 1979_1999_tropics_subset_3mmhr.mat
% Create empty maps
rain_fake_timeseries = zeros(1152,241,320);
for i = 1:1152; % set longitude
%disp(i)
for j = 1:241; % set latitude
%disp(j)
%for k = 1:320; % create map
%disp(k)
rain_fake_timeseries = datasample(rain_sample_1979_1999,1,3);
%disp(rain_fake_timeseries)
%save random_clus_fake_timeseries.mat rain_fake_timeseries -v7.3;
%end
end
end
save random_clus_fake_timeseries.mat rain_fake_timeseries -v7.3;
This is because you are not properly indexing into your time series array to store the data. What you are doing is that you are only saving the last randomly chosen slice in your time series array. If you look at your loop closely, you are simply overwriting the output array at each iteration of the for loop.
You are also not creating your for loop correctly. If I understand you correctly, each location in a slice represents a unique (x,y) coordinate. For each matrix that you have, you want to sample from this exact same location but temporally search through your ~2500 time instances. As such, you need to use all of your loop variables i, j and k to index into your 3D matrix. You also need to access all time slices at position (i,j) and randomly sample from all of the slices. If I can suggest a small optimization change, we can do this with only two for loops rather than three, randomly choose 320 points at this position for all of the time slices, and store it into the 3D matrix.
In other words:
clear all;
clc;
% Load datafile
load 1979_1999_tropics_subset_3mmhr.mat
% Create empty maps
rain_fake_timeseries = zeros(1152,241,320);
for i = 1 : size(rain_fake_timeseries,1)
for j = 1 : size(rain_fake_timeseries,2)
rain_fake_timeseries(i,j,:) = datasample(rain_sample_1979_1999(i,j,:), ...
size(rain_fake_timeseries,3), 3);
end
end
save random_clus_fake_timeseries.mat rain_fake_timeseries -v7.3;
Note that I have replaced the dimensions in the for loop with calls to size so that you can easily change the size of the matrices and it'll still work without you having to change any constants.

For Loop not advancing

I'm trying to read in a large number of jpg files using a for loop. But for some reason, the k index is not advancing. I just get A as a 460x520x3 uint8. Am I missing something?
My goal with this code is to convert all the jpg images to the same size. Since I haven't been able to advance through the images, I can't quite tell if I'm doing it right.
nFrames = length(date); % Number of frames.
for k = 1:nFrames-1 % Number of days
% Set file under consideration
A = imread(['map_EUS_' datestr(cell2mat(date_O3(k)),'yyyy_mm_dd') '_O3_MDA8.jpg']);
% Size of existing image A.
[rowsA, colsA, numberOfColorChannelsA] = size(A);
% Read in and get size of existing image B (the next image).
B = imread(['map_EUS_' datestr(cell2mat(date_O3(k+1)),'yyyy_mm_dd') '_O3_MDA8.jpg']);
[rowsB, colsB, numberOfColorChannelsB] = size(B);
% Size of B does not match A, so resize B to match A's size.
B = imresize(B, [rowsA colsA]);
eval(['print -djpeg map_EUS_' datestr(cell2mat(date_O3(k)),'yyyy_mm_dd') '_O3_MDA8_test.jpg']);
end
end
As you use imread to read the image in, it makes sense to use imwrite to write it out, rather than print/eval (also you should always think twice about using eval in MATLAB, and then think again).
You could also speed up this code somewhat - you just want to resize all the images to the size of whichever the first one is, so you don't need to keep reading in images to measure the size of them. Use imfinfo to get the size, then read in, resize, and write out B only.

Error using ' Transpose on ND array is not defined?

I am getting error for my below code: temp=reshape(img',irow*icol,1);
Error message:Error using '
Transpose on ND array is not defined.
What is solution for this. I think I have to use permute(A,order) command. But I dont know how to use this command in my code. Do you know any solution?
for i=1:M
str=strcat(int2str(i),'.jpg'); %concatenates two strings that form the name of the image
eval('img=imread(str);');
subplot(ceil(sqrt(M)),ceil(sqrt(M)),i)
imshow(img)
if i==3
title('Training set','fontsize',18)
end
drawnow;
[irow icol]=size(img); % get the number of rows (N1) and columns (N2)
temp=reshape(img',irow*icol,1); %creates a (N1*N2)x1 matrix
S=[S temp]; %X is a N1*N2xM matrix after finishing the sequence
%this is our S
end
I assume the code was designed for grey scale images. For matrices with more than two dimensions, you have to use permute. One solution could be:
[irow icol d]=size(img);
temp=reshape(permute(img,[2,1,3]),[irow*icol,d]);
Which results in a nx3 matrix, each column corresponding to one colour. You have to change the last line as well, but I don't know what you are expecting. Maybe take a look at cat

Matlab Plot Smoothing having no effect

I'm currently having some trouble with the 'smooth' command, namely that it seems to have no effect on the generated plot. I have already used the following script to generate a plot
for h=1:4
linespec = {'rx', 'gx', 'bx', 'yx'};
hold on
for b=1:365
y=mean(mean(A(b,6*(h-1)+1:6*h)));
p(h)=plot(b,y,linespec{h});
end
hold off
end
Going row by row in data set A and taking the average of the values in the first six columns, then column 7 through 12, 13 through 18 and 19 through 14; generating four plots in total.
The next step was to smooth the resultant plot by averaging the values over a span of 9. So, I tweaked the script to the following;
for h=1:4
linespec = {'rx', 'gx', 'bx', 'yx'};
hold on
for b=1:365
y=mean(mean(A(b,6*(h-1)+1:6*h)));
w = smooth(y,9,'moving');
p(h)=plot(b,w,linespec{h});
end
hold off
end
Essentially just adding the w variable and replacing y with w in the plot command. Yet this has no effect whatsoever on my plot. Matlab doesn't throw up any errors either, so there doesn't seem to be a problem with the input size. Does anyone have an idea as to what the issue might be?
In either version of the loop, you appear to be plotting individual values of y against individual values of b. I presume, then, that y is a single value. You can't smooth a point, so the smooth operation is having no effect.
From the start, you don't need to make a loop to calculate the various means; mean can take a 2D matrix and return a vector. Calculate y in one go, then smooth that vector (should have length 365, I presume - depends on the size of input A). e.g.:
b = 1:365;
y=mean(A(:,6*(h-1)+1:6*h),2);
w = smooth(y,9,'moving');
plot(b,y,'rx');
hold on
plot(b,w,'gx');