MATLAB: Create movie from cell array of uint8 images - image

I have 20 grayscale images of type uint8 stored in a 1x20 cell array named flow8. I want to generate a movie from them. My current approach is:
% Generate images.
for i = 1:20
flow8{i} = round(rand(100, 100)*255+1);
end
% Get into 4-D shape.
n = size(flow8,2);
matSize = size(flow8,1);
imageStack = reshape(cell2mat(flow8),matSize,[],n);
imageStack = permute(imageStack, [1 2 4 3]);
% Create movie.
mov = immovie(imageStack, gray)
implay(mov)
Here, I have added an image generation loop to make the code compilable.
With this code, the generated movie consists of only one horizontal line.
What do I need to do to get a proper movie? Or is there a better way to make a movie from my images?
I am using MATLAB R2015b academic on Windows 7.

If you look closely at your code, flow8 is 1 x 20. When you do your reshaping, you compute matSize with:
matSize = size(flow8, 1)
Well, that value is 1, because as we said the shape of the cell array is 1 x 20.
Instead, you likely wanted the size of each image. In which case, you'll want to index into the cell array to get the value and then take the size of that.
matSize = size(flow8{1});
Potentially another (much shorter) way to do this though, it so use cat to concatenate along the 4th dimension. Then you avoid all of the reshape and permute manipulations.
imageStack = cat(4, flow8{:});

Related

How to resize an image by adding extra pixels using matlab

I would like to resize a 512X512 image into 363X762 image which will be larger than the original image(of size 512X512). Those extra pixel values must be different values in the range of 0-255.
I tried the following code:
I=imread('photo.jpg'); %photo.jpg is a 512X512 image
B=zeros(363,726);
sizeOfMatrixB=size(B);
display(sizeOfMatrixB);
B(1:262144)=I(1:262144);
imshow(B);
B(262155:263538)=0;
But I think this is a lengthy one and the output is also not as desired. Could anyone suggest me with a better piece of code to perform this. Thank you in advance.
I think that the code you have is actually pretty close to ideal except that you have a lot of hard-coded values in there. Those should really be computed on the fly. We can do that using numel to count the number of elements in B.
B = zeros(363, 726);
%// Assign the first 262144 elements of B to the values in I
%// all of the rest will remain as 0
B(1:numel(I)) = I;
This flexibility is important and the importance is actually demonstrated via the typo in your last line:
B(262155:263538)=0;
%// Should be
B(262144:263538)=0;
Also, you don't need these extra assignments to zero at the end because you initialize the matrix to be all zeros in the first place.
A Side Note
It looks like you are spreading the original image data for each column across multiple columns. I'm guessing this isn't what you want. You probably only want to grab the first 363 rows of I to be placed into B. You can do that this way:
B = zeros(363, 726);
B(1:size(B, 1), 1:size(I, 2)) = I(1:size(B, 1), :);
Update
If you want the other values to be something other than zero, you can initialize your matrix to be that value instead.
value = 2;
B = zeros(363, 726) + value;
B(1:numel(I)) = I;
If you want them to be random integers between 0 and 255, use randi to initialize the matrix.
B = randi([0 255], 363, 726);
B(1:numel(I)) = I;

How can I crop several and random batches from an image?

I have an image of size (224 x 224) and I want to extract a number of random patches from the original image using Matlab (let say 5 patches). One of these patch should be at the centre of the original image. The patch size is (128 x 128).
I have tried this to crop just the centre patch:
II = imread('img.png')
[p3, p4] = size(II);
q1 = 50; // size of the crop box
i3_start = floor((p3-q1)/2); % or round instead of floor; using neither gives warning
i3_stop = i3_start + q1;
i4_start = floor((p4-q1)/2);
i4_stop = i4_start + q1;
II = II(i3_start:i3_stop, i4_start:i4_stop, :);
figure ,imshow(II);
I've tried to accomplish this in the following way:
A=imread('Lena.bmp');%sample image
rnd_x = randperm(size(A,1)-128,5);%choose 5 tandom unique points on x-axis
rnd_y = randperm(size(A,2)-128,5);%choose 5 tandom unique points on y-axis
for ii = 1:5
piece{ii} = A((rnd_x(ii):(rnd_x(ii)+127)),(rnd_y(ii):(rnd_y(ii)+127)),1:3);%Convert chosen numbers to image pieces
figure(ii)
imshow(piece{ii});
end
This takes image like this:
This gives 5 pics like this:
Here our image size is 512x512. So, if we want to cut the 128x128 piece from it, we need to seek from 385x385 grid (512-127). We find 5 random points on the grid expressed in rnd_x and rnd_y. Finally, we take the found points as the upper-left corners of the pieces and construct 128x128 images from them. The 5 pieces are recorded in piece cell array.
EDIT: forgot to add how to extract the center patch. The following code performs the task:
A=imread('Lena.bmp');%sample image
if mod(size(A,1),2)
A = A(1:(end-1),:,:);
end
if mod(size(A,2),2)
A = A(:,1:(end-1),:);
end
while size(A,1) > 128
A = A(2:(end-1),:,:);
end
while size(A,2) > 128
A = A(:,2:(end-1),:);
end
imshow(A)
The code removes one pixel from each side until we get the 128-pixel image.
Careful! In your code, if you load a color image (3 channels) and call size with only two outputs, you will have an incorrect value for p4.
Use three outputs when loading images to avoid this problem:
[nrows ncols nchannels] = size(II);
Your code correctly extracts a (q1 x q1) from the center of the image.
If you want a random patch just generate a random integer for the top-left column of the patch with the correct range to ensure that it doesn't fall outside the image. You can generate random integers using the function randi.
i3_start = randi(floor((p3-q1));
i4_start = randi(floor((p4-q1));
The rest of the code is the same. If you want several patches you can generate several values when calling the randi function with a second and third parameter for the desired number of rows and columns. And then process each patch inside a for loop.
BTW: In the third line you have an invalid Matlab comment (use % for comments). Also you should name your variables with more intuitive names.
Eg: [nrows ncols nchannels] = size(II);

Remove spacing in matlab subplot

How should i remove the empty space between these images?i need to combine all these images without any space.
bot=imread('bot.jpeg');
for i= 1:25
subplot(5,5,i),imshow(bot);
end
You need to specify axes' 'Position' property when you create them with subplot.
Also, you have to adjust figure aspect ratio to match that of the image, so that all figures fit without vertical or horizontal space.
If you show a different image in each subplot, all images should have the same aspect ratio, otherwise it's not possible for them to fit in the figure without empty spaces.
bot = imread('peppers.png');
for i= 1:25
subplot('Position',[(mod(i-1,5))/5 1-(ceil(i/5))/5 1/5 1/5])
imshow(bot); %// or show a different image on each subplot
end
p = get(gcf,'Position');
k = [size(bot,2) size(bot,1)]/(size(bot,2)+size(bot,1));
set(gcf,'Position',[p(1) p(2) (p(3)+p(4)).*k]) %// adjust figure x and y size
The most canonical way would be to take a look at this answer by bla here. This answer uses a function from the MATLAB File Exchange in order to achieve the answer. However, that requires learning a new function and playing around with the parameters.
If you want something working immediately, instead of showing each subimage in a separate grid on a plot, I would simply create a new image that stacks all of those images together:
bot_new = repmat(bot, [5 5]);
imshow(bot_new);
repmat takes a matrix and duplicates / stacks / tiles itself together for as many rows and as many columns (or in any dimension) that you want. In this case, I chose to stack the image so that there are 5 rows and 5 columns of it. We next show the stacked image together with imshow.
If we used an example image from MATLAB:
bot = imread('onion.png');
If we ran the above code that tiles the images together and showed the image, this is what we get:
I copy the answer from mathworks:
For each subplot, store its handle.
h = subplot(2,3,1);
Then set the 'position' property of h to be anything you want.
p = get(h, 'pos');
This is a 4-element vector [left, bottom, width, height] which
by default is in normalized coordinates (percentage of
figure window). For instance, to add 0.05 units (5% of
figure window) to the width, do this:
p(3) = p(3) + 0.05;
set(h, 'pos', p);
The SUBPLOT command picks standard values for these
parameters, but they could be anything you want. You
could put axes anywhere on the figure you want,
any size you want.
You can check for it:
http://www.mathworks.com/matlabcentral/newsreader/view_thread/144116

Resize an image with bilinear interpolation without imresize

I've found some methods to enlarge an image but there is no solution to shrink an image. I'm currently using the nearest neighbor method. How could I do this with bilinear interpolation without using the imresize function in MATLAB?
In your comments, you mentioned you wanted to resize an image using bilinear interpolation. Bear in mind that the bilinear interpolation algorithm is size independent. You can very well use the same algorithm for enlarging an image as well as shrinking an image. The right scale factors to sample the pixel locations are dependent on the output dimensions you specify. This doesn't change the core algorithm by the way.
Before I start with any code, I'm going to refer you to Richard Alan Peters' II digital image processing slides on interpolation, specifically slide #59. It has a great illustration as well as pseudocode on how to do bilinear interpolation that is MATLAB friendly. To be self-contained, I'm going to include his slide here so we can follow along and code it:
Please be advised that this only resamples the image. If you actually want to match MATLAB's output, you need to disable anti-aliasing.
MATLAB by default will perform anti-aliasing on the images to ensure the output looks visually pleasing. If you'd like to compare apples with apples, make sure you disable anti-aliasing when comparing between this implementation and MATLAB's imresize function.
Let's write a function that will do this for us. This function will take in an image (that is read in through imread) which can be either colour or grayscale, as well as an array of two elements - The image you want to resize and the output dimensions in a two-element array of the final resized image you want. The first element of this array will be the rows and the second element of this array will be the columns. We will simply go through this algorithm and calculate the output pixel colours / grayscale values using this pseudocode:
function [out] = bilinearInterpolation(im, out_dims)
%// Get some necessary variables first
in_rows = size(im,1);
in_cols = size(im,2);
out_rows = out_dims(1);
out_cols = out_dims(2);
%// Let S_R = R / R'
S_R = in_rows / out_rows;
%// Let S_C = C / C'
S_C = in_cols / out_cols;
%// Define grid of co-ordinates in our image
%// Generate (x,y) pairs for each point in our image
[cf, rf] = meshgrid(1 : out_cols, 1 : out_rows);
%// Let r_f = r'*S_R for r = 1,...,R'
%// Let c_f = c'*S_C for c = 1,...,C'
rf = rf * S_R;
cf = cf * S_C;
%// Let r = floor(rf) and c = floor(cf)
r = floor(rf);
c = floor(cf);
%// Any values out of range, cap
r(r < 1) = 1;
c(c < 1) = 1;
r(r > in_rows - 1) = in_rows - 1;
c(c > in_cols - 1) = in_cols - 1;
%// Let delta_R = rf - r and delta_C = cf - c
delta_R = rf - r;
delta_C = cf - c;
%// Final line of algorithm
%// Get column major indices for each point we wish
%// to access
in1_ind = sub2ind([in_rows, in_cols], r, c);
in2_ind = sub2ind([in_rows, in_cols], r+1,c);
in3_ind = sub2ind([in_rows, in_cols], r, c+1);
in4_ind = sub2ind([in_rows, in_cols], r+1, c+1);
%// Now interpolate
%// Go through each channel for the case of colour
%// Create output image that is the same class as input
out = zeros(out_rows, out_cols, size(im, 3));
out = cast(out, class(im));
for idx = 1 : size(im, 3)
chan = double(im(:,:,idx)); %// Get i'th channel
%// Interpolate the channel
tmp = chan(in1_ind).*(1 - delta_R).*(1 - delta_C) + ...
chan(in2_ind).*(delta_R).*(1 - delta_C) + ...
chan(in3_ind).*(1 - delta_R).*(delta_C) + ...
chan(in4_ind).*(delta_R).*(delta_C);
out(:,:,idx) = cast(tmp, class(im));
end
Take the above code, copy and paste it into a file called bilinearInterpolation.m and save it. Make sure you change your working directory where you've saved this file.
Except for sub2ind and perhaps meshgrid, everything seems to be in accordance with the algorithm. meshgrid is very easy to explain. All you're doing is specifying a 2D grid of (x,y) co-ordinates, where each location in your image has a pair of (x,y) or column and row co-ordinates. Creating a grid through meshgrid avoids any for loops as we will have generated all of the right pixel locations from the algorithm that we need before we continue.
How sub2ind works is that it takes in a row and column location in a 2D matrix (well... it can really be any amount of dimensions you want), and it outputs a single linear index. If you're not aware of how MATLAB indexes into matrices, there are two ways you can access an element in a matrix. You can use the row and column to get what you want, or you can use a column-major index. Take a look at this matrix example I have below:
A =
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
If we want to access the number 9, we can do A(2,4) which is what most people tend to default to. There is another way to access the number 9 using a single number, which is A(11)... now how is that the case? MATLAB lays out the memory of its matrices in column-major format. This means that if you were to take this matrix and stack all of its columns together in a single array, it would look like this:
A =
1
6
11
2
7
12
3
8
13
4
9
14
5
10
15
Now, if you want to access element number 9, you would need to access the 11th element of this array. Going back to the interpolation bit, sub2ind is crucial if you want to vectorize accessing the elements in your image to do the interpolation without doing any for loops. As such, if you look at the last line of the pseudocode, we want to access elements at r, c, r+1 and c+1. Note that all of these are 2D arrays, where each element in each of the matching locations in all of these arrays tell us the four pixels we need to sample from in order to produce the final output pixel. The output of sub2ind will also be 2D arrays of the same size as the output image. The key here is that each element of the 2D arrays of r, c, r+1, and c+1 will give us the column-major indices into the image that we want to access, and by throwing this as input into the image for indexing, we will exactly get the pixel locations that we want.
There are some important subtleties I'd like to add when implementing the algorithm:
You need to make sure that any indices to access the image when interpolating outside of the image are either set to 1 or the number of rows or columns to ensure you don't go out of bounds. Actually, if you extend to the right or below the image, you need to set this to one below the maximum as the interpolation requires that you are accessing pixels to one over to the right or below. This will make sure that you're still within bounds.
You also need to make sure that the output image is cast to the same class as the input image.
I ran through a for loop to interpolate each channel on its own. You could do this intelligently using bsxfun, but I decided to use a for loop for simplicity, and so that you are able to follow along with the algorithm.
As an example to show this works, let's use the onion.png image that is part of MATLAB's system path. The original dimensions of this image are 135 x 198. Let's interpolate this image by making it larger, going to 270 x 396 which is twice the size of the original image:
im = imread('onion.png');
out = bilinearInterpolation(im, [270 396]);
figure;
imshow(im);
figure;
imshow(out);
The above code will interpolate the image by increasing each dimension by twice as much, then show a figure with the original image and another figure with the scaled up image. This is what I get for both:
Similarly, let's shrink the image down by half as much:
im = imread('onion.png');
out = bilinearInterpolation(im, [68 99]);
figure;
imshow(im);
figure;
imshow(out);
Note that half of 135 is 67.5 for the rows, but I rounded up to 68. This is what I get:
One thing I've noticed in practice is that upsampling with bilinear has decent performance in comparison to other schemes like bicubic... or even Lanczos. However, when you're shrinking an image, because you're removing detail, nearest neighbour is very much sufficient. I find bilinear or bicubic to be overkill. I'm not sure about what your application is, but play around with the different interpolation algorithms and see what you like out of the results. Bicubic is another story, and I'll leave that to you as an exercise. Those slides I referred you to does have material on bicubic interpolation if you're interested.
Good luck!

Male/Female Classification with Matlab- About Finding Mean Image

I am working on a project which is about pattern (male/female)classification with matlab.I have a problem, I need your help, please.
My program should find mean images of datasets. First dataset is women,second dataset is men. So first mean image has to look like a woman and second a man.I have different datasets which all have format of jpeg. I am trying different datasets for my program to check if it is working but when I use different datasets I can not see true mean images all the time, for ex:
They are mean images from a dataset:
But when I use another dataset my mean images are like this, they have no meanings, I mean they dont look like face:
What can be the reason for this? I should work with different datasets. Please help.
`
filenamesA = dir(fullfile(pathfora, '*.jpg'));
Train_NumberA = numel(filenamesA);
%%%%%%%%%%%%%%%%%%%% Finding Image Vectors for A
imagesA= [];
for k = 1 : Train_NumberA
str = int2str(k);
str= strcat(str);
str = strcat('\',str,'b','.jpg');
str = strcat(pathfora,str);
imgA = imread(str);
imgA = rgb2gray(imgA);
[irowA icolA] = size(imgA);
tempA = reshape(imgA',irowA*icolA,1); % Reshaping 2D images into 1D image vectors
imagesA = [imagesA tempA]; % 'imagesA' grows after each turn
imagesA=double(imagesA);
end`
`%%%%%%%%%%%%%%%%%%%%%%%% Calculate the MEAN IMAGE VECTOR for A
mean_vectorA= mean(imagesA,2); % Computing the average vector m = (1/P)*sum(Tj's) (j = 1 : P)
mean_imageA= reshape(mean_vectorA,irowA,icolA); % Average matrix of training set A
meanimgA=mat2gray(mean_imageA);
figure(1);
imshow(rot90(meanimgA,3));`
-------------------------------------And same for dataset B (male)
You could use a 3D matrix to store the images. I also cleaned up the code a bit. Not tested.
filenamesA = dir(fullfile(pathfora, '*.jpg'));
Train_NumberA = numel(filenamesA);
imagesA = [];
for k = 1:Train_NumberA
imgA = imread(strcat(pathfora, '\', int2str(k), 'b', '.jpg'));
imgA = rgb2gray(imgA);
imagesA = cat(3, imagesA, imgA);
end
double command moved out of loop.
imagesA = double(imagesA);
Calculate the mean over the 3rd dimension of the imagesA matrix to get the mean 2D image.
meanimage_A = mean(imagesA, 3);
Convert to grayscale image.
meanimgA = mat2gray(meanimage_A);
I think rot90 is not needed here...
figure(1);
imshow(meanimgA, 3);
Use a 3D array or cell array of images instead of reshaping 2D images into single rows of a matrix. The reshaping is unnecessary and can only add bugs.
If all your images are the same size, you can use a multidimensional array: Matlab documentation on multidimensional arrays
Otherwise, use a cell array: Matlab documentation on cell arrays

Resources