Reputation: 1475
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!
Upvotes: 1
Views: 100
Reputation: 104484
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
Upvotes: 3