I'm having a hard time figuring out transformation between spaces using ind2sub and sub2ind. Could someone help? The problem is as follows:
I have a mask Y (or region-of-interest) in which voxel values are either 1 or zero: Y=72x72x33 double. I then find all the voxels with value of 1 (there are 15 of them) then use ind2sub to get the x y z coordinates for these voxels:
indx = find(Y>0);
[x,y,z] = ind2sub(size(Y),indx);
XYZ = [x y z]';
Since there are 15 voxels with the value of 1, I end up with XYZ=3x15 double, containing coordinates of these 15 voxels, something like this:
25 26 24 25 26 ...26
28 28 29 29 29 ...30
8 8 8 8 8 ...9
Based on some arbitrary criteria, I remove 6 voxels so XYZ become 3x9 double. Let's call this new_XYZ. Now I would like to transform this new_XYZ back into a mask (let's call it new_Y). I tried this:
new_Y=sub2ind(size(Y),new_XYZ);
Here, I probably did something wrong with the sub2ind since new_Y didn't give me what I expected. The dimensions are also not 72x72x33. The old mask is a sphere so I expect the new mask to be close to that. Instead, I get a straight line. Can someone help me with the transformation?
Thanks.
A.
There are a couple of things wrong in your approach. To detail I'll use a slightly smaller sample data set, but the explanation can scale up to any size.
Y = randi(10,5,5,3)-5 ;
This create a 5x5x3
containing random integers numbers from -5 to 5 (so a good chance to have about half of them positive (>0).
Before I go further, you can get a direct mask of your condition in the same shape of your matrix:
mask_positive_Y = Y>0 ;
>> whos mask_positive_Y
Name Size Bytes Class Attributes
mask_positive_Y 5x5x3 75 logical
This gives you an array of logical (boolean), the same size of your matrix, containing 0 (false
) everywhere and 1 (true
) where your condition is validated (Y>0
).
If you can work directly with this mask, you do not need to use ind2sub
and sub2ind
back and forth. For example, doing Y(mask_positive_Y) = NaN;
would replace all the values indicated by the mask with NaN
.
Since you want to modify the mask (remove some points), you may still need to get their indices, in which case you can simply call:
indx = find( mask_positive_Y ) ; %// will give the same result as: indx = find(Y>0);
Now let's assume you got your indices the way you specified, removed the 6 points and got your new_XYZ
matrice. The way to rebuild the mask is as follow.
ind2sub
gave you 3 vectors as output, and right enough, sub2ind
will expect 3 vectors as input (not a 3 column matrix as you did). So you will have to decompose your new_XYZ
into 3 vectors before you send it to sub2ind
.
new_indx = sub2ind(size(Y), new_XYZ(:,1) , new_XYZ(:,2) , new_XYZ(:,3) );
But don't forget that you did transpose your result matrix when you did XYZ = [x y z]';
, so make sure your new_XYZ
is also transposed back with new_XYZ = new_XYZ.' ;
before you decompose it in the code line above (or simply send the lines of new_XYZ
instead of the columns as showed).
By the way, the proper transpose
shorthand notation is .'
(and not simply '
which is the Complex conjugate transpose
).
Now this new_indx
is only a new vector of linear indices, homogeneous to the indx
you had earlier. You could already use this to assign values under the mask, but if you want a new mask the same shape than your matrix Y
, you have to go a bit further:
new_Ymask = false( size(Y) ) ; %// build an empty mask (false everywhere)
new_Ymask(new_indx) = true ; %// assign true to the masked values
This will be the same size as your initial matrix Y
, but also the same size as the first boolean mask I showed you mask_positive_Y
.