Split matrix into non-overlapping submatrices - matlab

I have an image of any size that I need to split into non-overlapping regions of 15x15 pixels. Previously I looked this up and used the following code:
newIm = rand(size(im2, 1),size(im2, 2));
subIm = mat2cell(newIm, 15*ones(size(newIm,1)/15,1), 15*ones(size(newIm,2)/15,1));
My problem is that I may not always be able to split the matrix into nice 15x15 regions. How can I fix this? Also, can you explain what exactly happens? I'd like to understand Matlab better for future use!

If you use the above code with a size not perfectly divisible by 15 (say 160), you will get the following error in MATLAB:
Input arguments, D1 through D2, must sum to each dimension of the input matrix size, [160 160].'
So you have to make your second and third input arguments of mat2cell sum to 160. Then you are done.
Code taken from here
blockSize=[15 15];
wholeBlockRows = floor(size(newIm,1)/ blockSize(1));
blockVectorR = [blockSize(1) * ones(1, wholeBlockRows), rem(size(newIm,1), blockSize(1))];
wholeBlockCols = floor(size(newIm,2)/ blockSize(2));
blockVectorC = [blockSize(2) * ones(1, wholeBlockCols), rem(size(newIm,2), blockSize(2))];
% sum of blockVectorR and blockVectorC will be equal to size(newIm,1) and
% size(newIm,2) respectively.
ca = mat2cell(newIm, blockVectorR, blockVectorC, size(newIm,3));
In your output cell array, you will see sub-images in the last row and column where either rows or columns (or both) are equal to: rem(size(newIm,1), blockSize(1)) or (and) rem(size(newIm,2), blockSize(2))

Related

Count number of unique symbols for a Buckingham Pi calculation in an expression with MATLAB

I am trying to write a script that goes through the Buckingham Pi theorem given a list of variables, each having a dimension. The set of dimensions do not need to be unique (it can contain repeats) only the same size as the set of variables.
clc, clear, close all
syms M L T Theta
dimen = [M,L,T,Theta]
mass - M
length - L
time - T
temperature - Theta
(I can add in other dimensions like electric current later, but for now, I want to get it working with these four).
Here is what I have so far in MatLab.
A = L^2; % maybe an area
V = L/T; % maybe a velocity
D = M/L^3; % maybe a density
% This the array of the combinations
param = {A,V,D};
I want to count how many of the syms M L T and Theta show up in my cell param.
For example starting at the first entry in the cell array.
param{1} = A
L^2
At this step, it should count that L has shown up once, and the others 0 times each.
param{2} = V
L/T
At this step, it counts that L has shown up once, but since it was already counted so I don't want to count it again. It should also count that T has shown up once. So far 1 L, and 1 T.
param{3} = D
M/L^3
Finally, this count that M has shown up once. So far 1 L, 1 T, and 1 M.
Since there are four possible symbols, I want to end the algorithm with this.
j = num; % how many times each of the syms was counted at least once.
If a dimension is not counted, that is fine. I am only interested in counting how many times each of the dimensions in the cell array are counted at least once. I will then use these to solve a system of equations to identify dimensionless groups.
I've received some suggestions based on other answers that I am providing below.
How to extract powers of a symbolic polynomial?
present = cellfun(#(expr), ismember(dimen, symvar(expr)), param, 'UniformOutput', false)
counts = sum(vertcat(present{:}), 1)
This last suggestions gives this error.
Error using cellfun
Input #2 expected to be a cell array, was sym instead.
Addendum
Removing the comma as suggested in the comments/answer still gives the same error. I am using release 2021b and a mlx file.
cellfun expects a cell array as its second argument: by introducing a comma between #(expr) and ismember(dimen, symvar(expr)) it's as if you were asking cellfun to iterate over the content of ismember(dimen, symvar(expr)), which is not what you really want, as that's the body of the anonymous function you are passing to cellfun as first argument.
The correct way of using cellfun is shown in the following script:
clc, clear, close all
syms M L T Theta
dimen = [M,L,T,Theta]
A = L^2; % maybe an area
V = L/T; % maybe a velocity
D = M/L^3; % maybe a density
% This the array of the combinations
param = {A,V,D};
% Counts the appearences of each dimension in each param
% and stores them in a cell array of vectors
present = cellfun(#(expr) ismember(dimen, symvar(expr)), param, 'UniformOutput', false)
% Unpack the cell array of vectors and
% compute the total number of appearences of each dimension
counts = sum(vertcat(present{:}), 1)

Error in vector lengths in matlab but i checked them with length() and theyre equal

l1=length(A)
l2=length(L)
%Residual
V=A*X-L
S= (V'*P*V)/(6-2);
%adjusted values
Z=V+L
%plot of observed valued of y
plot(X,L)
%plot of adjusted value of Y
plot(X,Z);
%Covariance Matrices for all Given Quantities can be Obtained by:
Cov_X= S*inv(N)
Cov_La=S*(A*N*A')
Cov_V= S*(inv(P)-A*inv(N)*A')
the output is
HA01
l1 =
6
l2 =
6
V =
-16.7888
-31.4848
110.0764
-3.8431
-51.1036
-6.8562
Z =
1.0e+03 *
0.9685
1.0886
1.2161
1.2905
1.3390
1.4506
Error using plot
Vectors must be the same length.
Error in HA01 (line 24)
plot(X,L)
i expected i accidently created different sized vectors etc but length are same yet it refuses to plot. please help i need to submit this in couple of hours.
length will tell you how many elements its has, but not its shape.
If you do size(X) and size(L) you will likely see that one is, say, 1x6 and the other one 6x1. Transpose one of them so they are the same size, not the same length.

Optimize nested for loop for calculating xcorr of matrix rows

I have 2 nested loops which do the following:
Get two rows of a matrix
Check if indices meet a condition or not
If they do: calculate xcorr between the two rows and put it into new vector
Find the index of the maximum value of sub vector and replace element of LAG matrix with this value
I dont know how I can speed this code up by vectorizing or otherwise.
b=size(data,1);
F=size(data,2);
LAG= zeros(b,b);
for i=1:b
for j=1:b
if j>i
x=data(i,:);
y=data(j,:);
d=xcorr(x,y);
d=d(:,F:(2*F)-1);
[M,I] = max(d);
LAG(i,j)=I-1;
d=xcorr(y,x);
d=d(:,F:(2*F)-1);
[M,I] = max(d);
LAG(j,i)=I-1;
end
end
end
First, a note on floating point precision...
You mention in a comment that your data contains the integers 0, 1, and 2. You would therefore expect a cross-correlation to give integer results. However, since the calculation is being done in double-precision, there appears to be some floating-point error introduced. This error can cause the results to be ever so slightly larger or smaller than integer values.
Since your calculations involve looking for the location of the maxima, then you could get slightly different results if there are repeated maximal integer values with added precision errors. For example, let's say you expect the value 10 to be the maximum and appear in indices 2 and 4 of a vector d. You might calculate d one way and get d(2) = 10 and d(4) = 10.00000000000001, with some added precision error. The maximum would therefore be located in index 4. If you use a different method to calculate d, you might get d(2) = 10 and d(4) = 9.99999999999999, with the error going in the opposite direction, causing the maximum to be located in index 2.
The solution? Round your cross-correlation data first:
d = round(xcorr(x, y));
This will eliminate the floating-point errors and give you the integer results you expect.
Now, on to the actual solutions...
Solution 1: Non-loop option
You can pass a matrix to xcorr and it will perform the cross-correlation for every pairwise combination of columns. Using this, you can forego your loops altogether like so:
d = round(xcorr(data.'));
[~, I] = max(d(F:(2*F)-1,:), [], 1);
LAG = reshape(I-1, b, b).';
Solution 2: Improved loop option
There are limits to how large data can be for the above solution, since it will produce large intermediate and output variables that can exceed the maximum array size available. In such a case for loops may be unavoidable, but you can improve upon the for-loop solution above. Specifically, you can compute the cross-correlation once for a pair (x, y), then just flip the result for the pair (y, x):
% Loop over rows:
for row = 1:b
% Loop over upper matrix triangle:
for col = (row+1):b
% Cross-correlation for upper triangle:
d = round(xcorr(data(row, :), data(col, :)));
[~, I] = max(d(:, F:(2*F)-1));
LAG(row, col) = I-1;
% Cross-correlation for lower triangle:
d = fliplr(d);
[~, I] = max(d(:, F:(2*F)-1));
LAG(col, row) = I-1;
end
end

How do I reshape a non-quadratic matrix?

I have a column vector A with dimensions (35064x1) that I want to reshape into a matrix with 720 lines and as many columns as it needs.
In MATLAB, it'd be something like this:
B = reshape(A,720,[])
in which B is my new matrix.
However, if I divide 35604 by 720, there'll be a remainder.
Ideally, MATLAB would go about filling every column with 720 values until the last column, which wouldn't have 720 values; rather, 504 values (48x720+504 = 35064).
Is there any function, as reshape, that would perform this task?
Since I am not good at coding, I'd resort to built-in functions first before going into programming.
reshape preserves the number of elements but you achieve the same in two steps
b=zeros(720*ceil(35604/720),1); b(1:35604)=a;
reshape(b,720,[])
A = rand(35064,1);
NoCols = 720;
tmp = mod(numel(A),NoCols ); % get the remainder
tmp2 = NoCols -tmp;
B = reshape([A; nan(tmp2,1)],720,[]); % reshape the extended column
This first gets the remainder after division, and then subtract that from the number of columns to find the amount of missing values. Then create an array with nan (or zeros, whichever suits your purpose best) to pad the original and then reshape. One liner:
A = rand(35064,1);
NoCols = 720;
B = reshape([A; nan(NoCols-mod(numel(A),NoCols);,1)],720,[]);
karakfa got the right idea, but some error in his code.
Fixing the errors and slightly simplifying it, you end up with:
B=nan(720,ceil(numel(a)/720));
B(1:numel(A))=A;
Create a matrix where A fits in and assingn the elemnent of A to the first numel(A) elements of the matrix.
An alternative implementation which is probably a bit faster but manipulates your variable b
%pads zeros at the end
A(720*ceil(numel(A)/720))=0;
%reshape
B=reshape(A,720,[]);

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.