フィルターのクリア

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 Center および File ExchangeInterpolation についてさらに検索

製品


リリース

R2019a

Community Treasure Hunt

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

Start Hunting!

Translated by