필터 지우기
필터 지우기

Edge interpolation in 2D-matrix bounded by NaNs

조회 수: 3 (최근 30일)
Klemen D
Klemen D 2019년 12월 20일
편집: Klemen D 2019년 12월 20일
I would like to obtain "smooth" envelope between numeric values and NaNs by interpolating "transition region" accordingly.
I have a 4x6 2D-matrix Z, which contains numeric elements and NaN entries. The numeric entries are bounded by NaNs i.e. both forms two distinctive regions.
a = 1:4; % vector in 1st dimension
b = 1:6; % vector in 2nd dimension
Z = [ 1 1 1 1 1 1;
5 5 5 5 5 5;
NaN 4 4 4 4 NaN;
NaN NaN 3 3 NaN NaN];
Then I Interpolate gridded data using griddedInterpolant
[X1, X2] = ndgrid(a,b);
Z_fun = griddedInterpolant(X1,X2,Z,'linear');
Z_fun.ExtrapolationMethod = 'linear'; % explicitly set extrapolation method
The test then gives me
x1_vec=1:0.1:4;
x2_vec=1:0.1:6;
[X1_vec, X2_vec] = ndgrid(x1_vec,x2_vec);
Z_int = Z_fun(X1_vec, X2_vec);
contourf(X1_vec,X2_vec,Z_int);
It is obvious that griddedInteropolant works only on domain defined by numeric entries in matrix Z, for example
Z_fun(2.5,1.6)
returns NaN. While this makes (some) sense to me, I wonder if I can nevertheless query for a point in small regions between numeric and NaN entries? I am actually interested only in points, which are closer to numeric entries than NaNs (e.g. 2.5,1.6), in order to obtain smoother transition between numeric and NaN values.

채택된 답변

Matt J
Matt J 2019년 12월 20일
편집: Matt J 2019년 12월 20일
The goal is to have a function that would linearly interpolate between succesive "edges" in Z matrix.
Consider using scattered interpolation instead,
a = 1:4; % vector in 1st dimension
b = 1:6; % vector in 2nd dimension
Z = [ 1 1 1 1 1 1;
5 5 5 5 5 5;
NaN 4 4 4 4 NaN;
NaN NaN 3 3 NaN NaN];
[A,B]=ndgrid(a,b);
I=~isnan(Z);
Z_fun=scatteredInterpolant(A(I),B(I),Z(I),'linear','none');
For example, Z_fun(2.5,1.6) should return some numeric value, but Z_fun(2.5,1.4) should (still) return NaN.
So far, so good:
>> Z_fun(2.5,1.6)
ans =
4.5000
>> Z_fun(2.5,1.4)
ans =
NaN
  댓글 수: 1
Klemen D
Klemen D 2019년 12월 20일
편집: Klemen D 2019년 12월 20일
Beautiful!
Testing above code with
x1_vec=1:0.01:4;
x2_vec=1:0.01:6;
[X1_vec, X2_vec] = ndgrid(x1_vec,x2_vec);
Z_int = Z_fun(X1_vec, X2_vec);
contourf(X1_vec,X2_vec,Z_int);
returns the desired result.Please, add this snippet to your solution.

댓글을 달려면 로그인하십시오.

추가 답변 (1개)

Image Analyst
Image Analyst 2019년 12월 20일
You can replace the nan's by a distance-weighted average of nearby non-nan values, like in a 3x3 window. Try this and see if it satisfies you:
Z = [ 1 1 1 1 1 1;
5 5 5 5 5 5;
NaN 4 4 4 4 NaN;
NaN NaN 3 3 NaN NaN]
% Count the number of non-nans in a 3-by-3 window
nanMap = isnan(Z)
counts = conv2(~nanMap, ones(3), 'same')
% Get the sums of the non-nan values in the 3-by-3 window
Z_sums = Z;
Z_sums(isnan(Z)) = 0;
% Make a "linear distance"-weighted kernel
kernel = ones(3) / sqrt(2);
kernel(2,:) = 1;
kernel(:, 2) = 1
% Use that kernel to get distance weighted sums at each point.
sums = conv2(Z_sums, kernel, 'same')
% Divide them to get the average of non-nans in a 3-by-3 window.
Z_means = sums ./ counts
% Replace nan values with the average values, leaving non-nan values alone.
Z_repaired = Z; % Initialize as Z so we can leave the non-nan values alone.
Z_repaired(nanMap) = Z_means(nanMap)
In the command window you'll see:
Z =
1 1 1 1 1 1
5 5 5 5 5 5
NaN 4 4 4 4 NaN
NaN NaN 3 3 NaN NaN
nanMap =
4×6 logical array
0 0 0 0 0 0
0 0 0 0 0 0
1 0 0 0 0 1
1 1 0 0 1 1
counts =
4 6 6 6 6 4
5 8 9 9 8 5
3 6 8 8 6 3
1 3 5 5 3 1
kernel =
0.70711 1 0.70711
1 1 1
0.70711 1 0.70711
sums =
10.536 15.071 15.071 15.071 15.071 10.536
14.536 24.243 27.071 27.071 24.243 14.536
12.536 22.192 29.192 29.192 22.192 12.536
2.8284 9.8284 15.657 15.657 9.8284 2.8284
Z_means =
2.6339 2.5118 2.5118 2.5118 2.5118 2.6339
2.9071 3.0303 3.0079 3.0079 3.0303 2.9071
4.1785 3.6987 3.649 3.649 3.6987 4.1785
2.8284 3.2761 3.1314 3.1314 3.2761 2.8284
Z_repaired =
1 1 1 1 1 1
5 5 5 5 5 5
4.1785 4 4 4 4 4.1785
2.8284 3.2761 3 3 3.2761 2.8284
  댓글 수: 3
Image Analyst
Image Analyst 2019년 12월 20일
Try imresize(). And give an example of the output you'd want.
If you just want to put in some arbitrary locations, then you'd probably be best off just using bilinear or bicubic interpolation. I don't think there is any routine in MATLAB where you can put in 4 corner values, and an interior location and get the interpolated value at the interior location, though it's simple enough to do. See : Wikipedia: Bilinear interpolation in image processing
imresize() does interpolation but you have to give it a known output image size, so the values would be interpolated at regular, periodic, known locations, not arbitrary locations.
Klemen D
Klemen D 2019년 12월 20일
I have added a graphical representation of the situation.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Interpolation에 대해 자세히 알아보기

제품


릴리스

R2019a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by