Change 1D vector (nx1) to 3D matrix (1x1xn) - matlab

Given a= [1;2;3] I want to change this to b where b is
b(1,1,1) = 1
b(1,1,2) = 2
b(1,1,3) = 3.
How can I do this? Is there no built-in command for this?

Use permute to throw the first dimension back at the end as third dimension and bring the third and second dimensions to the front (their orders won't matter). Thus, we would have two such implementations, like so -
permute(a,[3 2 1])
permute(a,[2 3 1])
You can also use reshape to push back the elements to the third dimension, like so -
reshape(a,1,1,numel(a))
Little tutorial on permute
A 3D array A without any permute(rearrangement of dimensions) changes would be : permute(A,[1 2 3]).
Now, any permuting you do, would be w.r.t. the original order of [1 2 3]. Let's say you want to swap 1st and 3rd dimensions, so swap the 1 and 3 in [1 2 3], giving us [3 2 1] and use it as the second argument in permute.
Here's to make your permuting skills stronger - Let's say, you swap first and third dimensions and then you do some processing on this permuted 3D array. Now, you want to get back to the original order, so you need to swap back the 1st and 3rd dimensions. So, you use [3,2,1] again, like so - permute(permute(A,[3 2 1]),[3 2 1]) and this would be essentially permute(A,[1 2 3]) and yes that's A, back to home!

You can also use
b = shiftdim(a,-2);
As per the documenation,
B = shiftdim(X,N) shifts the dimensions of X by N. When N is
positive, shiftdim shifts the dimensions to the left and wraps the
N leading dimensions to the end. When N is negative, shiftdim
shifts the dimensions to the right and pads with singletons.
A singleton dimension [or simpliy "singleton"] is any dimension dim for which size(A,dim) = 1.

Related

How to use logical conditions only for some dimensions in multidimensional arrays in MATLAB

Let us have a 4D matrix (tensor), output:
[X,Y,Z] = ndgrid(-50:55,-55:60,-50:60);
a = 1:4;
output = zeros([size(X),length(a)]);
Next, we determine the area inside the ellipsoid:
position = [0,0,0];
radius = [10,20,10];
test_func = #(X,Y,Z) ((X-position(1))/radius(1)).^2 ...
+ ((Y-position(2))/radius(2)).^2 ...
+ ((Z-position(3))/radius(3)).^2 <= 1;
condition = test_func(X,Y,Z);
I need to fill the matrix output inside the ellipsoid for the first 3 dimensions. But for the fourth dimension I need to fill a. I need to do something like this:
output(condition,:) = a;
But it does not work. How to do it? Any ideas please!
If I understand your question correctly, you have a 4D matrix where each temporal blob of pixels in 3D for each 4D slice is filled with a number... from 1 up to 4 where each number tells you which slice you're in.
You can cleverly use bsxfun and permute to help you accomplish this task:
output = bsxfun(#times, double(condition), permute(a, [1 4 3 2]));
This takes a bit of imagination to imagine how this works but it's quite simple. condition is a 3D array of logical values where each location in this 3D space is either 0 if it doesn't or 1 if it does belong to a point inside an ellipsoid. a is a row vector from 1 through 4 or however many elements you want this to end with. Let's call this N to be more general.
permute(a, [1 4 3 2]) shuffles the dimensions such that we create a 4D vector where we have 1 row, 1 column and 1 slice but we have 4 elements going into the fourth dimension.
By using bsxfun in this regard, it performs automatic broadcasting on two inputs where each dimension in the output array will match whichever of the two inputs had the largest value. The condition is that for each dimension independently, they should both match or one of them is a singleton dimension (i.e. 1).
Therefore for your particular example, condition will be 106 x 116 x 111 while the output of the permute operation will be 1 x 1 x 1 x N. condition is also technically 106 x 116 x 111 x 1 and using bsxfun, we would thus get an output array of size 106 x 116 x 111 x N. Performing the element-wise #times operation, the permuted vector a will thus broadcast itself over all dimensions where each 3D slice i will contain the value of i. The condition matrix will then duplicate itself over the fourth dimension so we have N copies of the condition matrix, and performing the element-wise multiply thus completes what you need. This is doable as the logical mask you created contains only 0s and 1s. By multiplying element-wise with this mask, only the values that are 1 will register a change. Specifically, if you multiply the values at these locations by any non-zero value, they will change to these non-zero values. Using this logic, you'd want to make these values a. It is important to note that I had to cast condition to double as bsxfun only allows two inputs of the same class / data type to be used.
To visually see that this is correct, I'll show scatter plots of each blob where the colour of each blob would denote what label in a it belongs to:
close all;
N = 4;
clrs = 'rgbm';
figure;
for ii = 1 : N
blob = output(:,:,:,ii);
subplot(2,2,ii);
plot3(X(blob == ii), Y(blob == ii), Z(blob == ii), [clrs(ii) '.']);
end
We get:
Notice that the spatial extent of each ellipsoid is the same but what is different are the colours assigned to each blob. I've made it such that the values for the first blob, or those assigned to a = 1 are red, those that are assigned to a = 2 are assigned to green, a = 3 to blue and finally a = 4 to magenta.
If you absolutely want to be sure that the coordinates of each blob are equal across all blobs, you can use find in each 3D blob individually and ensure that the non-zero indices are all equal:
inds = arrayfun(#(x) find(output(:,:,:,x)), a, 'un', 0);
all_equal = isequal(inds{:});
The code finds in each blob the column major indices of all non-zero locations in 3D. To know whether or not we got it right, each 3D blob should all contain the same non-zero column major indices. The arrayfun call goes through each 3D blob and returns a cell array where each cell element is the column major indices for a particular blob. We then pipe this into isequal to ensure that all of these column major indices arrays are equal. We get:
>> all_equal
all_equal =
1

How to generate evenly space for a vector?

Generating evenly space can use linspace, but I wonder if I can vectorize it. What I mean is as follow:
Given an input vector, say [1 2], I want to generate a 2X6 matrix such that:
in the first row, the entries are [0:0.2:1]
the entries for the second row are [0:0.4:2]
In general, the input vector may not be known, it can change from [1 2] to [1:3:10] or other vectors. However, the first column much be a zero vector and the number of columns can be treated to be the known in advanced.
I do not want to write it using a for loop if possible.
Assuming A = [x, y], you can generate the desired 2 x 6 matrix M as follows:
B = A/A(1);
M = B.'*linspace(0, A(1), 6);

Dividing each slice of a MATLAB 3D array by a different number

I have a 3D MATLAB function.
I want to multiply each slice of the matrix by a different number.
I tried to implement this by bsxfun in the following example code:
a=randi(10,4,3,2);
b=[2 3];
c=bsxfun(#times,a,b)
I intended that the first 4*3 slice of 'a' would be multiplied by 2, and the second 4*3 slice of 'a' would be multiplied by 3.
However, I only got the following error:
??? Error using ==> bsxfun
Non-singleton dimensions of the two
input arrays must match each other.
How to solve the problem without using a loop?
As the error says, you need to make the dimensions of the vector and the matrix match. Since b is a row vector, you can make the slices of the matrix into columns. You can do this with permute:
a = randi(10, 4, 3, 2);
b = [2 3];
ap = permute(a, [1 3 2]);
c = bsxfun(#times, ap, b)
Then, to get the result matrix back into the correct shape, you need to permute again. You can either figure out the correct permutation order (it happens to be the same in this case, i.e. [1 3 2]) or you can use ipermute (inverse permute) and let it figure it out for you. Just give it the same permutation order you gave permute earlier.
c = ipermute(c, [1 3 2]);
Alternatively, you can permute the vector b to be the right shape to multiply the slices by making it extend in the 3rd dimension:
a = randi(10, 4, 3, 2);
b = [2 3];
bp = permute(b, [1 3 2]);
c = bsxfun(#times, a, bp)
In this case, since we didn't change a, we don't have to permute c again to get the correct shape.

Check element wise equality of a 3D matrix Matlab

I have a 3D matrix say for eg. A(10x5x8). I need to get a 2D matrix (Boolean) out of it of size 10x5.
True if its elemental 3 Dimensional values are all same. i.e. Result(1,1) = 1 if A(1,1,1) == A(1,1,2) == A(1,1,3) etc..
False if at least one is different.
I expect a vectored approach which is fast and efficient.
Sample input:
A(:,:,1) = 1 2
2 2
A(:,:,2) = 1 1
2 3
Expected Output:
Result = 1 0
1 0
Use bsxfun with the eq function and use the first slice as the first input and compare with the other slices for the second input. Allow the first input to broadcast itself over the multiple slices.
Once you do that, use all and check the third dimension:
ind1 = bsxfun(#eq, A(:,:,1), A(:,:,2:end);
ind2 = all(ind1, 3);
The logic behind the above is very simple. How the first line of code works is that you would create a temporary matrix that would take the first slice of A and let it duplicate itself for as many slices as you have in A, without the first slice. Once you do this, you would do an element-by-element equality with this temporary matrix and the other slices. If you had a 3D column that was all equal, the one element from the first slice would be compared with every single value that corresponds to the same 3D column. Should they all equal to each other, then you would get a 3D column of all logical 1s. Therefore, to have a 3D column that is all equal to each other, all of the values should be 1, which is why all is used - to check if all values in a 3D column are equal to 1. Should all of the 3D column be a logical 1, we have matched your criteria.
Example run
>> A1 = [1 2; 2 2];
>> A2 = [1 1; 2 3];
>> A3 = [1 3; 2 4];
>> A4 = [1 5; 2 6];
>> A = cat(3, A1, A2, A3, A4);
>> ind1 = bsxfun(#eq, A(:,:,1), A(:,:,2:end);
>> ind2 = all(ind1, 3)
ind2 =
1 0
1 0
I made a matrix of 4 slices where the 3D column at the top left corner and the bottom left corner have all of the same values. Once you run through the code at the beginning of the post, we get what you expect.
Here's with short and sweet diff and must be quite memory efficient -
out = ~any(diff(A,[],3),3)
So, basically with diff along the third dimension diff(..[],3), you would calculate differences between the same (i,j) but on different 3D slices. Thus, if all such diff outputs are zeros, that would indicate that all dim3 elements for the same (i,j) are the same. This all zeros information is then picked up by ~any() also along dim3 with ~any(.,3) for the desired 2D array output.

How to put 1st dimension along 3rd in Matlab?

Suppose I have a matrix
A=[1 2 3]
which is row matrix. Not I want to do it "page" matrix, i.e. align elements along 3rd dimension.
I noticed, that the following
A=permute(A,[3 1 2])
works, while the following
A=permute(A,[3 2 1])
does not.
Why?
Your question is not really clear. If I'm right you'd like your matrix to become B = [0,0,1;0,0,2; 0,0,3].
This can be done easily with the transpose function by typing:
B(:,:,3)=A'
Instead of using the permute function which is a generalization of transpose. Also, your operation might not "work" because permute is an operation that affects the dimension of the array, and not of its elements
Note that the size of A is [1 3], not [3 1]. As CST-Link points out, this is equivalent with [1 3 1 1] etc., since the singleton dimensions are removed.
size(A,1) = 1
size(A,2) = 3 <-- You want this to be the third dimension
size(A,3) = 1
Now, what you want to do is align the second dimension (the one telling you how many columns you have) to the third dimension (the one telling you how many slices you have).
When you use permute, you specify the order you want the original dimensions to occur. I.e. if you do permute(A, [2 1]) for a vector, you will transpose it. The second dimension is now the first and vice versa. You want the second dimemsion to be the third, and keep the first dimension constant, so:
permute(A, [1 3 2])
If you do:
permute(A, [3 2 1])
you will take the third dimension to be the first (size(A,1) = 1), the second dimension (size(A,2) = 3) will be the second (i.e. it is not changed), and the first dimension is the third. Thus, the only dimensions that change are the first and third. These are both 1 to begin with, so nothing has changed.
Note that you can also use shiftdim in this particular case:
shiftdim(A,-1)