How to make a block of matrices from large matrix in matlab? - matlab

I have a 256x256 matrix from that I want to create block of 8x8 matrices. I have a below code which shows just one block i want all the blocks then subtract a number from each element of the matrix. When i do the subtract 128 from each element it doesn't show negative values rather showing only 0.
[x,y] = size(M);
for i=1:8
for j=1:8
k(i,j) = M(i,j);
end
end
disp(k);
for a=1:size(k)
for b=1:size(k)
A(a,b) = k(a,b) - 128;
end
end
disp(A);

well, if you have to subtract a fixed value it's better to do it as
M = M - 128;
It's faster.
You said you get 0 values instead of negative ones; it is likely due to the type of the matrix which is unsigned (i.e. the guys are just positive). A cast to general integer is necessary. Try:
M = int16(M) - 128;
To obtain the partition I propose the following, there can be more efficient ways, btw:
r = rand(256,256); %// test case, substitute with your matrix M
[i j] = meshgrid(1:8:256); %// lattice of indices
idx = num2cell([ i(:) , j(:) ],2); %// cell version
matr = cellfun( #(i) r(i(1):i(1)+7,i(2):i(2)+7), idx, 'UniformOutput',false); %// blocks
matr will contain all the sub-matrices in lexicographical order. e.g.
matr{2}
ans =
0.4026 0.3141 0.4164 0.5005 0.6952 0.1955 0.9803 0.5097
0.8186 0.9280 0.1737 0.6133 0.8562 0.7405 0.8766 0.0975
0.2704 0.8333 0.1892 0.7661 0.5168 0.3856 0.1432 0.9958
0.9973 0.8488 0.6937 0.2630 0.1004 0.5842 0.1844 0.5206
0.4052 0.0629 0.6982 0.1530 0.9234 0.1271 0.7317 0.3541
0.2984 0.3633 0.1510 0.0297 0.0225 0.7945 0.2925 0.0396
0.5097 0.0802 0.8744 0.1032 0.8523 0.6150 0.4845 0.5703
0.8635 0.0194 0.1879 0.5017 0.5297 0.6319 0.2406 0.5125
Explanation: In matlab you can efficiently operate on matrices and slices of them. For instance, you can easily copy submatrices, e.g. the first 8x8 matrix is
sub = M(1:8,1:8);
You want all the submatrices, thus you need kind of a lattice of indices to get
sub_ij = M(1+8*(i-1) : 7 * 8*(i-1) , 1+8*(j-1) : 7 * 8*(j-1))
i.e. you need the lattice
(1+8*(i-1) : 7 * 8*(i-1) , 1+8*(j-1) : 7 * 8*(j-1)) % // for all i,j
you can use meshgrid for that.
Finally you have to cut off the pieces, that is what the last two instruction do. particularly the first one generates the indices (try idx{1},...), and the second one generates the submatrices (try matr{1},...).

Hope this code helps you. It has 16x16 image to divide into 4x4 blocks. You may change the value and get the required output as you like.

Related

How to vectorize code with 3 loops that generates a matrix

Could you help me to vectorise this Matlav code constructing a matrix A of dimension MNx(2+N-1)xR in order to speed it up? At the moment it takes approx. 8 sec
INITIALISING
R=200;
M=400;
N=20;
B=[kron((1:1:M)', ones(N,1)) repmat((1:1:N)', M,1)]; %(MN)x(2)
B looks like
B=[1 1;
1 2;
...;
1 20;
2 1;
2 2;
...
2 20;
...
400 20]
CODE
A=[ repmat(B,1,1,R) zeros(M*N,N-1,R)]; %Allocate the space
%(MN)x(2+N-1)x(R)
% I want A(:,1:2,r)=B for r=1,...,R
%Fill the remaining columns of A in the following way
for r=1:R
utemp1=randn(M*N, N-1); %Generate a matrix of random
%numbers of dimension (M*N)x(N-1)
utemp2=randn(M, N); %Generate a matrix of random
%numbers of dimension (M)x(N)
utemp3=zeros(M*N,N-1); %Generate a matrix of random
%numbers of dimension(M)x(N-1)
for m=1:M
for j=1:N
utemp3((m-1)*N+j,:)= utemp2(m,j)+[utemp2(m,1:j-1) utemp2(m,j+1:N)]; %(1)x(N-1)
%e.g. if m=2, j=3, I want to fill the 23th row of utemp3
%with utemp2(2,3)+[utemp2(2,1:2) utemp2(m,4:20)];
%e.g. if m=4, j=1, I want to fill the 61st row of utemp3
%with utemp2(4,1)+[utemp2(4,2:20)];
end
end
A(:,3:end,r)=utemp1+utemp3; %sum utemp1
end
SOME EXPLANATIONS
for r=1,...,R
A is such that
for m=1,...,M and for j=1,...,N
the row in A(:,:,r) starting with [m j] in the first two columns is filled in the remaining (N-1) columns with uj+uh+ujh for each h~=j, where uj, uh, ujh are i.i.d standard Gaussian numbers that can be found in utemp1 and utemp2.
You can precompute the indices and use them in 500 iterations:
idx = repmat(reshape(1:M*N,M,N).',1,N);
idx = reshape(idx(logical(kron(~eye(N),ones(1,M)))),N-1,[]).';
for k=1:500
for r=1:R
utemp2=randn(M*N,1);
A(:,3:end,r)=randn(M*N, N-1)+bsxfun(#plus,utemp2,utemp2(idx) );
end
end
However allocating large matrices ,specially of repeated elements, and vectorizing operations on it is not always the most efficient way. There are built-in functions that directly operate on the original array avoiding repeating elements of the array.

Large image matrix: save to small matrices

I'm new to MATLAB and its development. I have a image which is 1134 (rows) X 1134 (columns). I want that image to save 3 (columns) X 3 (rows). In order to do that I need 378 cells. For that I used following code, but it gives me an error.
image=imread('C:\Users\ven\Desktop\test\depth.png');
I=reshape(image,1,1134*1134);
chunk_size = [3 3]; % your desired size of the chunks image is broken into
sc = sz ./ chunk_size; % number of chunks in each dimension; must be integer
% split to chunk_size(1) by chunk_size(2) chunks
X = mat2cell(I, chunk_size(1) * ones(sc(1),1), chunk_size(2) *ones(sc(2),1));
Error:
Error using mat2cell (line 97)
Input arguments, D1 through D2, must sum to each dimension of the input matrix size, [1 1285956].'
Unfortunately your code does not work as you think it would.
The ./ operator performs point wise division of two matrices. Short example:
[12, 8] ./ [4, 2] == [12/4, 8/2] == [3, 4]
In order for it to work both matrices must have exactly the same size. In your case you try to perform such an operation on a 1134x1134 matrix (the image) and a 1x2 matrix (chunk_size).
In other words you can not use it to divide matrices into smaller ones.
However, a solution to your problem is to use the mat2cell function to pick out subsets of the matrix. A explanation of how it is done can be found here (including examples): http://se.mathworks.com/matlabcentral/answers/89757-how-to-divide-256x256-matrix-into-sixteen-16x16-blocks.
Hope it helps :)
Behind the C=A./B command is loop over all elements of A(ii,jj,...) and B(ii,jj,..) and each C(ii,jj,..)=A(ii,jj,...)/B(ii,jj,...).
Therefore martices A and B must be of same dimension.
If you want to split matrix into groups you can use
sc=cell(1134/3,1);
kk=0;ll=0;
for ii=2:3:1133
kk=kk+1;
for jj=2:3:1133
ll=ll+1;
sc{kk,ll}=image(ii-1:ii+1,jj-1:jj+1);
end
end
The code allocates cell array sc for resulting submatrices and arbitrary counters kk and ll. Then it loops over ii and jj with step of 3 representing centers of each submatrices.
Edit
Or you can use mat2cell command (type help mat2cell or doc mat2cell in matlab shell)
sc=mat2cell(image,3,3);
In both cases the result is cell array and its iith and jjth elements (matrices) are accessible by sc{ii,jj}. If you want call iith anr jjth number in kkth and llth matrix, do it via sc{kk,ll}(ii,jj).
In short, you divided a 1134 x 1134 by 2 x 1 matrix. That doesn't work.
The error "Matrix dimensions must agree**" is from the dividing a matrix with another matrix that doesn't have the right dimensions.
You used the scalar divide "./" which divided a matrix by another matrix.
You want something like:
n = 1134 / 3 % you should measure the length of the image
I1=image(1:n,1:n); % first row
I2=image(1:n,n:2n);
I3=image(1:n,2n:3n);
I4=image(n:2n,1:n); % second row
I5=image(n:2n,n:2n);
I6=image(n:2n,2n:3n);
I7=image(2n:3n,1:n); % third row
I8=image(2n:3n,n:2n);
I9=image(2n:3n,2n:3n);
from here:
http://au.mathworks.com/matlabcentral/answers/46699-how-to-segment-divide-an-image-into-4-equal-halves
There would be a nice loop you could do it in, but sometimes thinking is hard.

How to concatenate smaller matrices to form a larger matrix?

I would like to concatenate 14641 number of 3X3 matrices into a matrix of size 363X363 and the large matrix must contain 121 submatrices in each row(121*3=363 columns) and 121 such rows of submatrices(121*3=363rows).I have gone through the similar questions but I didn't get the correct logic to concatenate large number of matrices.
Awaiting your suggestions. Thanks in advance.
PS: I got those 3X3 matrices from a 363X363 matrix. The following code is for splitting the single matrix into submatrices.
I=imread('photo.jpg');
B = randi([0 255],363,726,3);
B(1:numel(I)) = I;
L=B(1:363,1:363);
[al,bl]=size(L);
ImageSize=al*bl;
BlockD=3; % i assume 3x3 block
BlockSize=BlockD*BlockD;
TotalBlocks=ImageSize/BlockSize;
subL=zeros(BlockD,BlockD,TotalBlocks); %arrays of blocks.
LL=double(L);
k=1;
for i=1:BlockD:al
for j=1:BlockD:bl
subL(:,:,k)=LL(i:i+BlockD-1,j:j+BlockD-1);
k=k+1;
end
end
Now I want to concatenate all these 'subL' submatrices to form 'LL' again
Using blocproc instead of above code
I tried using blockproc function instead of the above code. I did this piece of code and is working pretty well.Thank you
I=imread('photo.jpg');
B = randi([0 255],363,726,3);
B(1:numel(I)) = I;
L=B(1:363,1:363);
q=[1 2 3 4];
fun=#(block_struct)quaternionrotate(q,block_struct.data);
LL = blockproc(L,[3 3],fun);
and the function quaternionrotate is
function [ Lrot1 ] = quaternionrotate(q,A)
qinv=quatinv(q);
B=zeros(3,1);
A1=[B A];
Lrot=quatmultiply(q,quatmultiply(A1,qinv));
Lrot(:,1)=[];
Lrot1=Lrot;
end
Finally figured this out!
% I used this to make 14641 3x3 sample matrices, you should use your own
matrix = ones(3,3);
for i = 2:14641
matrix = [matrix, i*ones(3,3)];
end
c_size = 121;
output = cell(c_size, c_size) % Make 121x121 cell matrix
% Populate the cell matrix
for i = 1:1:c_size
for j = 1:1:c_size
output(i,j) = {matrix(1:3, (i-1)*c_size*3+(j-1)*3+1 : (i-1)*c_size*3+(j-1)*3+3)};
end
end
This breaks up the 43923x3 size matrix of 363 3x3 matrices into a 121x121 cell matrix of 3x3 matrices. Now that's a tongue twister...
Either way the code does what you need! :)

How can I build a Scilab / MATLAB program that averages a 3D matrix?

I need to make a scilab / MATLAB program that averages the values of a 3D matrix in cubes of a given size(N x N x N).I am eternally grateful to anyone who can help me.
Thanks in advance
In MATLAB, mat2cell and cellfun make a great team for working on N-dimensional non-overlapping blocks, as I think is the case in the question. An example scenario:
[IN]: A = [30x30x30] array
[IN]: bd = [5 5 5], size of cube
[OUT]: B = [6x6x6] array of block means
To accomplish the above, the solution is:
dims = [30 30 30]; bd = [5 5 5];
A = rand(dims);
f = floor(dims./bd);
remDims = mod(dims,bd); % handle dims that are not a multiple of block size
Ac = mat2cell(A,...
[bd(1)*ones(f(1),1); remDims(1)*ones(remDims(1)>0)], ....
[bd(2)*ones(f(2),1); remDims(2)*ones(remDims(2)>0)], ....
[bd(3)*ones(f(3),1); remDims(3)*ones(remDims(3)>0)] );
B = cellfun(#(x) mean(x(:)),Ac);
If you need a full size output with the mean values replicated, there is a straightforward solution involving the 'UniformOutput' option of cellfun followed by cell2mat.
If you want overlapping cubes and the same size output as input, you can simply do convn(A,ones(blockDims)/prod(blockDims),'same').
EDIT: Simplifications, clarity, generality and fixes.
N = 10; %Same as OP's parameter
M = 10*N;%The input matrix's size in each dimensiona, assumes M is an integer multiple of N
Mat = rand(M,M,M); % A random input matrix
avgs = zeros((M/N)^3,1); %Initializing output vector
l=1; %indexing
for i=1:M/N %indexing 1st coord
for j=1:M/N %indexing 2nd coord
for k=1:M/N % indexing third coord
temp = Mat((i-1)*N+1:i*N,(j-1)*N+1:j*N,(k-1)*N+1:k*N); %temporary copy
avg(l) = mean(temp(:)); %averaging operation on the N*N*N copy
l = l+1; %increment indexing
end
end
end
The for loops and copying can be eliminated once you get the gist of indexing.

Indexing of unknown dimensional matrix

I have a non-fixed dimensional matrix M, from which I want to access a single element.
The element's indices are contained in a vector J.
So for example:
M = rand(6,4,8,2);
J = [5 2 7 1];
output = M(5,2,7,1)
This time M has 4 dimensions, but this is not known in advance. This is dependent on the setup of the algorithm I'm writing. It could likewise be that
M = rand(6,4);
J = [3 1];
output = M(3,1)
so I can't simply use
output=M(J(1),J(2))
I was thinking of using sub2ind, but this also needs its variables comma separated..
#gnovice
this works, but I intend to use this kind of element extraction from the matrix M quite a lot. So if I have to create a temporary variable cellJ every time I access M, wouldn't this tremendously slow down the computation??
I could also write a separate function
function x= getM(M,J)
x=M(J(1),J(2));
% M doesn't change in this function, so no mem copy needed = passed by reference
end
and adapt this for different configurations of the algorithm. This is of course a speed vs flexibility consideration which I hadn't included in my question..
BUT: this is only available for getting the element, for setting there is no other way than actually using the indices (and preferably the linear index). I still think sub2ind is an option. The final result I had intended was something like:
function idx = getLinearIdx(J, size_M)
idx = ...
end
RESULTS:
function lin_idx = Lidx_ml( J, M )%#eml
%LIDX_ML converts an array of indices J for a multidimensional array M to
%linear indices, directly useable on M
%
% INPUT
% J NxP matrix containing P sets of N indices
% M A example matrix, with same size as on which the indices in J
% will be applicable.
%
% OUTPUT
% lin_idx Px1 array of linear indices
%
% method 1
%lin_idx = zeros(size(J,2),1);
%for ii = 1:size(J,2)
% cellJ = num2cell(J(:,ii));
% lin_idx(ii) = sub2ind(size(M),cellJ{:});
%end
% method 2
sizeM = size(M);
J(2:end,:) = J(2:end,:)-1;
lin_idx = cumprod([1 sizeM(1:end-1)])*J;
end
method 2 is 20 (small number of index sets (=P) to convert) to 80 (large number of index sets (=P)) times faster than method 1. easy choice
For the general case where J can be any length (which I assume always matches the number of dimensions in M), there are a couple options you have:
You can place each entry of J in a cell of a cell array using the num2cell function, then create a comma-separated list from this cell array using the colon operator:
cellJ = num2cell(J);
output = M(cellJ{:});
You can sidestep the sub2ind function and compute the linear index yourself with a little bit of math:
sizeM = size(M);
index = cumprod([1 sizeM(1:end-1)]) * (J(:) - [0; ones(numel(J)-1, 1)]);
output = M(index);
Here is a version of gnovices option 2) which allows to process a whole matrix of subscripts, where each row contains one subscript. E.g for 3 subscripts:
J = [5 2 7 1
1 5 2 7
4 3 9 2];
sizeM = size(M);
idx = cumprod([1 sizeX(1:end-1)])*(J - [zeros(size(J,1),1) ones(size(J,1),size(J,2)-1)]).';