Three dimensional (3D) matrix interpolation in Matlab

后端 未结 1 631
鱼传尺愫
鱼传尺愫 2020-12-16 08:20

I have a 3D matrix in Matlab of certain size, however I would need to interpolate it to obtain matrix of larger size.

size(M)
ans= 
  50   108    86
<         


        
相关标签:
1条回答
  • 2020-12-16 08:58

    You almost have it right. You need to define 3D Grid of co-ordinates. Creating single vectors is not the right way to do it. You can certainly use interp3 here. Try doing:

    [X,Y,Z] = meshgrid(1:213, 1:100, 1:140);
    Vq = interp3(M, X, Y, Z);
    

    Note that I have swapped the row (100) and column (213) limits, as the first parameter progresses horizontally while the second parameter progresses vertically.

    Also, by using interp3 in this fashion, we are assuming that the limits of X, Y and Z fall within 1:213, 1:100 and 1:140. Should you provide any values outside of these limits, you will get NaN. There are a couple of ways you can avoid this:

    1. Specify the spline flag at the end to allow for spline extrapolation
    2. If you want to resize the matrix (like if you were to resize an image), then there currently is no built-in method that can resize a 3D matrix this way. You'll have to write this yourself.

    If you want to do Step #2, you can do the following.

    First, you need to figure out the scale factors for each dimension. Basically this is the ratio of the output size of each dimension with the original input size.

    After this, you create a 2D grid that has its limits bounded by the original size of the input matrix, but the size of this grid will be of the size of the output matrix. The scale factor is useful here because this effectively gives us what each value in the grid should be to interpolate. We would create new co-ordinates that went from 1 to the output size of each dimension, in increments of 1/scaleFactor. As an example, if we wanted to double the size of our matrix, this is a factor of 2. If we had X and Y co-ordinates that went from 1 to 3 and 1 to 3 respectively, the original grid would look like this:

    X =            Y = 
    
    1  2  3        1  1  1
    1  2  3        2  2  2
    1  2  3        3  3  3
    

    To double this, this would simply be:

    X =                         Y = 
    
    1  1.5  2  2.5  3           1   1   1   1   1
    1  1.5  2  2.5  3          1.5 1.5 1.5 1.5 1.5
    1  1.5  2  2.5  3           2   2   2   2   2
    1  1.5  2  2.5  3          2.5 2.5 2.5 2.5 2.5 
    1  1.5  2  2.5  3           3   3   3   3   3
    

    Note that this create an output grid of 5 x 5. To make this doubled as 6 x 6, you can do whatever you want, but for the sake of simplicity, just duplicate the last row and last column, and so:

    X =                         Y = 
    
    1  1.5  2  2.5  3  3         1   1   1   1   1   1
    1  1.5  2  2.5  3  3        1.5 1.5 1.5 1.5 1.5 1.5
    1  1.5  2  2.5  3  3         2   2   2   2   2   2
    1  1.5  2  2.5  3  3        2.5 2.5 2.5 2.5 2.5 2.5
    1  1.5  2  2.5  3  3         3   3   3   3   3   3
    1  1.5  2  2.5  3  3         3   3   3   3   3   3
    

    This defines our grid of 2D columns for resizing. Now it's a matter of resize in 3D. What we can do is interpolate in between the slices. We can easily do this using permute in MATLAB, and I'll show you how to do that later. As such, the basic algorithm is this:

    • Determine the output size of the output matrix you want
    • Determine the scale factors in each dimension
    • Create a 2D grid of interpolated access values for each dimension following the procedure above
    • For each 2D slice in your matrix, use interp2 to resize each slice to the output rows and columns using the above 2D grid.
    • After, use interp1 and permute to resize the third dimension.

    Without further ado, here is the code to do this:

    %// Specify output size of your matrix here
    outputSize = [100 213 140];
    
    %//Figure out size of original matrix
    d = size(M);
    
    %//Scaling coefficients
    scaleCoeff = outputSize ./ d;
    
    %//Indices of original slices in 3D
    z = 1:d(3);
    
    %//Output slice indices in 3D
    zi=1:1/scaleCoeff(3):d(3);
    
    %//Create gridded interpolated co-ordinates for 1 slice
    [X,Y] = meshgrid(1:1/scaleCoeff(2):d(2), 1:1/scaleCoeff(1):d(1));
    
    %//We simply duplicate the last rows and last columns of the grid if
    %//by doing meshgrid, we don't get exactly the output size we want
    %//This is due to round off when perform 1/scaleCoeff(2) or
    %//1/scaleCoeff(1).  We would be off by 1.
    if size(X,1) ~= outputSize(1)
        X(end+1,:) = X(end,:);
        Y(end+1,:) = Y(end,:);
    end
    if size(X,2) ~= outputSize(2)
        X(:,end+1) = X(:,end);
        Y(:,end+1) = X(:,end);
    end
    
    %//For each slice...
    M2D = zeros(outputSize(1), outputSize(2), d(3));
    for ind = z
        %//Interpolate each slice via interp2
        M2D(:,:,ind) = interp2(M(:,:,ind), X, Y);
    end
    
    %//Now interpolate in 3D
    MFinal = permute(interp1(z,permute(M2D,[3 1 2]),zi),[2 3 1]);
    
    %//If the number of output slices don't match after we interpolate in 3D, we
    %//just duplicate the last slice again
    if size(MFinal,3) ~= outputSize(3)
        MFinal(:,:,end+1) = MFinal(:,:,end);
    end
    

    MFinal would be your final interpolated / resized 3D matrix. The key method to interpolate in 3D is the permute method. What this will do is that for each value of z, we will generate a 2D slice of values. As such, if we had a slice at z = 1 and one at z = 2, if we wanted to find what the 2D grid of values was at slice z = 1.5, this will generate a 2D slice that creates these interpolated values using information between z = 1 and z = 2. We do the first call of permute to do this, then another permute call to undo our permutation and get the original dimensions back.

    0 讨论(0)
提交回复
热议问题