Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
507 views
in Technique[技术] by (71.8m points)

octave - Three dimensional (3D) matrix interpolation in Matlab

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

I need that matrix to be interpolated and finally obtain a matrix of size 100x213x140. Any ideas of how to do it using interp3? Is this possible at all?

I've tried

Vq = interp3(M,1:100,1:213,1:140)
Error using griddedInterpolant/subsref
The input data has inconsistent size.

Error in interp3 (line 178)
    Vq = F(Xq,Yq,Zq);

If I use meshgrid:

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

Matlab seems to like it, however two things happen:

  1. size(Vq) ans= 213 100 140
  2. I can see NaN values in Vq

The reason behind is because I need to compare two matrices sampled at different frequency. So, I could either interpolate M to obtain a matrix of size 100x213x140 or "reduce" the size of my other matrix M2 of size 100x213x140 to 50x108x86. I thought the former should be easier and safer...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...