divide the image into 3*3 blocks - matlab

I have a matrix that does not happen to have dimensions that are multiples of 3 or it might.
How can we divide the entire image into blocks of 3*3 matrices.
(Can ignore the last ones which does not come under the 3*3 multiples.
Also, the 3*3 matrices can be be saved in arrays.
a=3; b=3; %window size
x=size(f,1)/a; y=size(f,2)/b; %f is the original image
m=a*ones(1,x); n=b*ones(1,y);
I=mat2cell(f,m,n);

I have never used mat2cell to divide matrices, and thinking about it now it seems like a really good idea. As I don't have MATLAB here in this computer, I'll describe the way I do it, which does not involve mat2cell.
Ignoring the last columns and rows is easy:
d = 3; % the dimension of the sub matrix
[x,y] = size(f);
% perform integer division by three
m = floor(x/d);
n = floor(y/d);
% find out how many cols and rows have to be left out
m_rest = mod(x,d);
n_rest = mod(y,d);
% remove the rows and columns that won't fit
new_f = f(1:(end-m_rest), 1:(end-n_rest));
% this steps you won't have to perform if you use mat2cell
% creates the matrix with (m,n) pages
new_f = reshape( new_f, [ d m d n ] );
new_f = permute( new_f, [ 1 3 2 4 ] );
Now you can access the sub-matrices like this:
new_f(:,:,1,1) % returns the 1st one
new_f(:,:,3,2) % returns the one at position [3,2]
If you'd like to use mat2cell to do that, you could do something like the following:
% after creating new_f, instead of the reshape, permute
cells_f = mat2cell(new_f, d*ones(1,m), d*ones(1,n));
Then you would access it in a different way:
cells_f{1,1}
cells_f{3,2}
The cell approach I cannot test because I don't have MATLAB on this PC, but if I can recall the usage of mat2cell correctly, it should work fine.
Hope it helps :)

Related

3D matrix, multiplication on last dimensions

I have a 3D-matrix A, with size lets say 3x12x100. The first two dimensions define 3×12 matrices, the latter one is simply the linear index. I want a very simple operation on these 100 matrices. For all these matrices, i want them multiplied with its conjugate transpose. With a very simple for loop, i can create this:
data = data;
A = zeros(100, 12, 12);
for i=1:100
A(i, :, :) = data(:, :, i)'*data(:, :, i);
end
But i like clean code, so i dont really prefer this for-loop. I have done some searching and sometimes find something like mtimesx (which is a custom made MATLAB function from 2010). I think i am missing something very obvious (as usual), because this seems a fairly easy operation (its just an "element-wise" matrix multiplication).
The size of my actual matrix is 3x12x862400. My original script takes about 10 minutes or longer, a variant on what #FangQ posts fixes it in a matter of seconds. My new code is as following, note that it still is under construction and i still need to validate it:
data = rand(3, 12, 862400) + i*rand(3, 12, 862400)
data2 = conj(permute(data, [2 1 3])); % conjugate transpose each matrix
% my data matrix contains 862400 3x12 matrices with complex numbers
Ap = permute(data2, [2 1 4 3]);
Bp = permute(data, [1 4 2 3]);
M = Ap.*Bp;
M = sum(M, 1);
M = permute(M, [2 3 4 1]);
#Cris was right, you can find an example from this MatlabCentral post
https://www.mathworks.com/matlabcentral/answers/10161-3d-matrix-multiplication#answer_413531

Multiplying two matrices by a vector

I am multiplying two matrices by a vector using loop. Is it possible to do that without using loop?
Something like D1=C.*(A.*B) is not working.
Below sample of code
clear;
clc;
A=rand(5,5);
B=rand(5,5);
C=[0.1 0.3];
for ii=1:2
D(:,:,ii)=A.*B.*C(ii);
end
this how to do it:
D=bsxfun(#times,A.*B,permute(C,[3 1 2]))
Explanation: the trick is to change C from a row vector (say x-direction) to the 3rd dimension (or z-direction) using permute, which is as if you would have defined C differently:
C(:,:,1)=0.1;
C(:,:,2)=0.3;
Now, bsxfun is a compact way to do the for loop you wrote. that's it.
You can do that with mostly matrix indexing:
clear;
clc;
A=rand(5,5);
B=rand(5,5);
C=[0.1 0.3];
% Get matrices to final size
A = A(:,:,ones(length(C),1)); % repeat into third dimension as many times as length(C)
B = B(:,:,ones(length(C),1)); % repeat into third dimension as many times as length(C)
C = C(ones(1,size(A,2)),:,ones(1,size(A,1))); % make it size size(A,2)xlength(C)xsize(A,1)
C = permute(C,[3 1 2]); % change to correct order
D = A.*B.*C;
Or as one liner (faster,requires less memory and doesn't change input variables):
D = A(:,:,ones(length(C),1)).*B(:,:,ones(length(C),1)).*permute(C(ones(1,size(A,2)),:,ones(1,size(A,1))),[3 1 2]);
Still, i think for most matrices sizes bsxfun is faster (and better readable). But solving stuff with indexing is a lot more fun :P

convert 3d matrix to 4d matrix using matlab

I have 2D matrixs of dimensions 400 x 500,each of these matrixs show an image. my process contain 2 steps:
1) I have to partition these images (split matrix to equal sized sub-matrices)
2) I have to save each of these split in one matrix
first step is done and dimention of matrix change from 2D-->3D (the last index shows index of splits)
now for the step 2 I have 100 images and I want to have matrix with 4 dimensions which the last index show the number of images
sample : for accessing split 3 of image 40 : [:,:,3,40]
I already try to using permut and reshape but not successful
here is my code
nCol = 10;
nRow = 4;
K=dir(p);
Len=length(K);
for i=3:Len
x1=imread(strcat(p,'\',K(i).name));
[m,n,d1]=size(x1);
if d1==1
x=double(x1);
else
x=double(rgb2gray(x1));
end
x=imresize(x,NN);
%% determined width and height of divided matrix %%%%%%%%%%%%%%%%%%%%%%%%%%
m = size(x,1)/nRow;
n = size(x,2)/nCol;
T = permute(reshape(permute(reshape(x, size(x, 1), n, []), [2 1 3]), n, m, []), [2 1 3]);
Im=[Im T(:,:,:,i-2)];
end
any idea would be appreciated.
reshape picks elements in column major ordering so you might have to write convoluted code to get it to work. Rather than going the way of using permute and reshape to create 4D matrices and potentially running into an out of memory issue I would advice the use of mat2cell to split your matrix into a cell array because mat2cell splits a matrix like you would want to split an image.
Here I show an example with an image
RGB = imread('peppers.png');
x = rgb2gray(RGB); % x is a 384 x 512 matrix, we want to split in 3 rows and 2 columns
x2 = mat2cell(x,384*ones(3,1)/3,512*ones(2,1)/2); % 2D cell array, each cell holds a part of the image
imshow(x2{1,1}) % Top left part of the image
You could loop over all your images and create a 3D cell array where each layer in the array represents each image split into pieces. I would suggest to preallocate you array and assign the matrix in the correct layer within the loop rather than incrementally increasing the size of your matrix.
Also there seems to be an Image processing toolbox specific function to do what you are trying to : Check this : How to divide an image into blocks in MATLAB?

Extract and then sum sub-matrices in Matlab [duplicate]

Given a square matrix of say size 400x400, how would I go about splitting this into constituent sub-matrices of 20x20 using a for-loop? I can't even think where to begin!
I imagine I want something like :
[x,y] = size(matrix)
for i = 1:20:x
for j = 1:20:y
but I'm unsure how I would proceed. Thoughts?
Well, I know that the poster explicitly asked for a for loop, and Jeff Mather's answer provided exactly that.
But still I got curious whether it is possible to decompose a matrix into tiles (sub-matrices) of a given size without a loop. In case someone else is curious, too, here's what I have come up with:
T = permute(reshape(permute(reshape(A, size(A, 1), n, []), [2 1 3]), n, m, []), [2 1 3])
transforms a two-dimensional array A into a three-dimensional array T, where each 2d slice T(:, :, i) is one of the tiles of size m x n. The third index enumerates the tiles in standard Matlab linearized order, tile rows first.
The variant
T = permute(reshape(A, size(A, 1), n, []), [2 1 3]);
T = permute(reshape(T, n, m, [], size(T, 3)), [2 1 3 4]);
makes T a four-dimensional array where T(:, :, i, j) gives the 2d slice with tile indices i, j.
Coming up with these expressions feels a bit like solving a sliding puzzle. ;-)
I'm sorry that my answer does not use a for loop either, but this would also do the trick:
cellOf20x20matrices = mat2cell(matrix, ones(1,20)*20, ones(1,20)*20)
You can then access the individual cells like:
cellOf20x20matrices{i,j}(a,b)
where i,j is the submatrix to fetch (and a,b is the indexing into that matrix if needed)
Regards
You seem really close. Just using the problem as you described it (400-by-400, divided into 20-by-20 chunks), wouldn't this do what you want?
[x,y] = size(M);
for i = 1:20:x
for j = 1:20:y
tmp = M(i:(i+19), j:(j+19));
% Do something interesting with "tmp" here.
end
end
Even though the question is basically for 2D matrices, inspired by A. Donda's answer I would like to expand his answer to 3D matrices so that this technique could be used in cropping True Color images (3D)
A = imread('peppers.png'); %// size(384x512x3)
nCol = 4; %// number of Col blocks
nRow = 2; %// number of Row blocks
m = size(A,1)/nRow; %// Sub-matrix row size (Should be an integer)
n = size(A,2)/nCol; %// Sub-matrix column size (Should be an integer)
imshow(A); %// show original image
out1 = reshape(permute(A,[2 1 4 3]),size(A,2),m,[],size(A,3));
out2 = permute(reshape(permute(out1,[2 1 3 4]),m,n,[],size(A,3)),[1 2 4 3]);
figure;
for i = 1:nCol*nRow
subplot(nRow,nCol,i); imshow(out2(:,:,:,i));
end
The basic idea is to make the 3rd Dimension unaffected while reshaping so that the image isn't distorted. To achieve this, additional permuting was done to swap 3rd and 4th dimensions. Once the process is done, the dimensions are restored as it was, by permuting back.
Results:
Original Image
Subplots (Partitions / Sub Matrices)
Advantage of this method is, it works good on 2D images as well.
Here is an example of a Gray Scale image (2D). Example used here is MatLab in-built image 'cameraman.tif'
With some many upvotes for the answer that makes use nested calls to permute, I thought of timing it and comparing to the other answer that makes use of mat2cell.
It is true that they don't return the exact same thing but:
the cell can be easily converted into a matrix like the other (I timed this, see further down);
when this problem arises, it is preferable (in my experience) to have the data in a cell since later on one will often want to put the original back together;
Anyway, I have compared them both with the following script. The code was run in Octave (version 3.9.1) with JIT disabled.
function T = split_by_reshape_permute (A, m, n)
T = permute (reshape (permute (reshape (A, size (A, 1), n, []), [2 1 3]), n, m, []), [2 1 3]);
endfunction
function T = split_by_mat2cell (A, m, n)
l = size (A) ./ [m n];
T = mat2cell (A, repmat (m, l(1), 1), repmat (n, l (2), 1));
endfunction
function t = time_it (f, varargin)
t = cputime ();
for i = 1:100
f(varargin{:});
endfor
t = cputime () - t;
endfunction
Asizes = [30 50 80 100 300 500 800 1000 3000 5000 8000 10000];
Tsides = [2 5 10];
As = arrayfun (#rand, Asizes, "UniformOutput", false);
for d = Tsides
figure ();
t1 = t2 = [];
for A = As
A = A{1};
s = rows (A) /d;
t1(end+1) = time_it (#split_by_reshape_permute, A, s, s);
t2(end+1) = time_it (#split_by_mat2cell, A, s, s);
endfor
semilogy (Asizes, [t1(:) t2(:)]);
title (sprintf ("Splitting in %i", d));
legend ("reshape-permute", "mat2cell");
xlabel ("Length of matrix side (all squares)");
ylabel ("log (CPU time)");
endfor
Note that the Y axis is in log scale
Performance
Performance wise, using the nested permute will only be faster for smaller matrices where big changes in relative performance are actually very small changes in time. Note that the Y axis is in log scale, so the difference between the two functions for a 100x100 matrix is 0.02 seconds while for a 10000x10000 matrix is 100 seconds.
I have also tested the following which will convert the cell into a matrix so that the return values of the two functions are the same:
function T = split_by_mat2cell (A, m, n)
l = size (A) ./ [m n];
T = mat2cell (A, repmat (m, l(1), 1), repmat (n, l (2), 1), 1);
T = reshape (cell2mat (T(:)'), [m n numel(T)]);
endfunction
This does slow it down a bit but not enough to consider (the lines will cross at 600x600 instead of 400x400).
Readability
It is so much more difficult to get your head around the use of the nested permute and reshape. It's mad to use it. It will increase maintenance time by a lot (but hey, this is Matlab language, it's not supposed to be elegant and reusable).
Future
The nested calls to permute does not expand nicely at all into N dimensions. I guess it would require a for loop by dimension (which would not help at all the already quite cryptic code). On the other hand, making use of mat2cell:
function T = split_by_mat2cell (A, lengths)
dl = arrayfun (#(l, s) repmat (l, s, 1), lengths, size (A) ./ lengths, "UniformOutput", false);
T = mat2cell (A, dl{:});
endfunction
Edit (and tested in Matlab too)
The amount of upvotes on the answer suggesting to use permute and reshape got me so curious that I decided to get this tested in Matlab (R2010b). The results there were pretty much the same, i.e., it's performance is really poor. So unless this operation will be done a lot of times, in matrices that will always be small (less than 300x300), and there will always be a Matlab guru around to explain what it does, don't use it.
If you want to use a for loop you can do this:
[x,y] = size(matrix)
k=1; % counter
for i = 1:20:x
for j = 1:20:y
subMatrix=Matrix(i:i+19, j:j+19);
subMatrixCell{k}=subMatrix; % if you want to save all the
% submatrices into a cell array
k=k+1;
end
end

How do I create a simliarity matrix in MATLAB?

I am working towards comparing multiple images. I have these image data as column vectors of a matrix called "images." I want to assess the similarity of images by first computing their Eucledian distance. I then want to create a matrix over which I can execute multiple random walks. Right now, my code is as follows:
% clear
% clc
% close all
%
% load tea.mat;
images = Input.X;
M = zeros(size(images, 2), size (images, 2));
for i = 1:size(images, 2)
for j = 1:size(images, 2)
normImageTemp = sqrt((sum((images(:, i) - images(:, j))./256).^2));
%Need to accurately select the value of gamma_i
gamma_i = 1/10;
M(i, j) = exp(-gamma_i.*normImageTemp);
end
end
My matrix M however, ends up having a value of 1 along its main diagonal and zeros elsewhere. I'm expecting "large" values for the first few elements of each row and "small" values for elements with column index > 4. Could someone please explain what is wrong? Any advice is appreciated.
Since you're trying to compute a Euclidean distance, it looks like you have an error in where your parentheses are placed when you compute normImageTemp. You have this:
normImageTemp = sqrt((sum((...)./256).^2));
%# ^--- Note that this parenthesis...
But you actually want to do this:
normImageTemp = sqrt(sum(((...)./256).^2));
%# ^--- ...should be here
In other words, you need to perform the element-wise squaring, then the summation, then the square root. What you are doing now is summing elements first, then squaring and taking the square root of the summation, which essentially cancel each other out (or are actually the equivalent of just taking the absolute value).
Incidentally, you can actually use the function NORM to perform this operation for you, like so:
normImageTemp = norm((images(:, i) - images(:, j))./256);
The results you're getting seem reasonable. Recall the behavior of the exp(-x). When x is zero, exp(-x) is 1. When x is large exp(-x) is zero.
Perhaps if you make M(i,j) = normImageTemp; you'd see what you expect to see.
Consider this solution:
I = Input.X;
D = squareform( pdist(I') ); %'# euclidean distance between columns of I
M = exp(-(1/10) * D); %# similarity matrix between columns of I
PDIST and SQUAREFORM are functions from the Statistics Toolbox.
Otherwise consider this equivalent vectorized code (using only built-in functions):
%# we know that: ||u-v||^2 = ||u||^2 + ||v||^2 - 2*u.v
X = sum(I.^2,1);
D = real( sqrt(bsxfun(#plus,X,X')-2*(I'*I)) );
M = exp(-(1/10) * D);
As was explained in the other answers, D is the distance matrix, while exp(-D) is the similarity matrix (which is why you get ones on the diagonal)
there is an already implemented function pdist, if you have a matrix A, you can directly do
Sim= squareform(pdist(A))