How do I interpolate and smoothen ndvi time series?
Show older comments
I have ununiformly distributed noisey ndvi time series. I want to interpolate and smoothen it using matlab. I am attaching the sample ndvi file and request you to please suggest me how to achieve it using matlab. I would appreciate your kind cooperation and help.
Jyoti
2 Comments
John D'Errico
on 19 Apr 2024
Edited: John D'Errico
on 19 Apr 2024
Assuming you mean each row of that table is a distinct time series, sampled as a function of the first row,
The signal to noise ratio appears to be low, at least if you look at any individual series.
The data series are VERY short, which makes it difficult to extract any signal.
There is one data point far away from the rest in x.
At the same time, ALL of those series have a very similar character.
data = readtable('sample_ndvi.csv');
t = table2array(data(1,2:end));
z = table2array(data(2:end,2:end));
surf(z)
xlabel 'Time'
ylabel 'Series'
I've left the time axis as a simple index, since that would just make it all far more dificult to visualize.
The point is, there appears to be a lot of signal, once you look at all of the sereis at once. They all have the same shapes, apparently very noisy. So exactly what smoothing would you want to do?
Accepted Answer
More Answers (1)
gauri
on 7 May 2024
0 votes
I am pasting the link for data. Please get the data from this link.
35 Comments
Mathieu NOE
on 13 May 2024
hello
I have downloaded the files , but how do you load these files in the workspace ?
are you using the Image Toolbox ? Identify Vegetation Regions Using Interactive NDVI Thresholding - MATLAB & Simulink - MathWorks France
gauri
on 13 May 2024
I read these files using code as follows;
d='C:\works\' % your directory
files = dir(fullfile(d, '*.dat'));
% Preallocate a 3D matrix to hold the data
stacked_image = zeros(numFiles, 1315, 1153);
numFiles = length(files);
for i = 1:numFiles;
% Read each file
img = hypercube(files(i).name);
% convert integer numbers into real numbers
data = single(img.DataCube);
red = data(:,:,2); % red band
nir = data(:,:,6); % near infrared band
ndvi = (nir - red) ./ (nir + red);
% Stack the image
stacked_image(i, :, :) = ndvi
end
I hope it will help to read these files.
Thanks for your kind help.
Mathieu NOE
on 14 May 2024
hello again
that is my trouble, you're using hypercube from the image processing toolbox (I don't have)
maybe you could run your code and save stacked_image array in a mat file and share this one (maybe very big )
I have stored the ndvi data in ndvi.mat file and uploaded it on following link;
I request you to please check it and let me know whether it is ok or not.
Mathieu NOE
on 14 May 2024
hmmm, it says could not access server , try later ...
does it work on your side ?
gauri
on 14 May 2024
Yes it does work on my side. I can download it here.
Mathieu NOE
on 14 May 2024
tried again but still have the same error
will try a bit later on
gauri
on 14 May 2024
I am again sending the link as follows;
I request you to please check this link.
Mathieu NOE
on 14 May 2024
it works !
Mathieu NOE
on 14 May 2024
so this is a first trial
idea was to replace "bad" images with nans then interpolate the 3D array using either one of these Fex submissions :
for the time being I did a manual selection of which images needed to be interpolated , but maybe a smarter approach is doable
the selection is based on the mean value of each image, we can see the drop in this curve
so we have 24 mean values and the graph looks like :

so I decided I wanted to interpolate image 7, 10,11 and 18
once we have corrected (interpolated) the images, we get a new mean curve :

full code :
load('ndvi.mat')
[m,n,p] = size(stacked_image);
mi = min(stacked_image,[],'all');
ma = max(stacked_image,[],'all');
x_axis = (1:m); % 12 months = 24 images
%% step1 : plot the raw data
for ck = 1:m
figure
data2D = squeeze(stacked_image(ck,:,:));
data2Dmean(ck) = mean(data2D,'all','omitnan');
imagesc(data2D);
caxis([mi ma]);
colorbar('vert');
end
% mean 2D raw data plot
figure
plot(x_axis,data2Dmean);
%% step 2 : identify images to be interpolated
ind = [7 10 11 18];% selected image to correct :
stacked_image2 = stacked_image;
stacked_image2(ind,:,:) = NaN;
% now do interpolation on selected images
% faster :
stacked_image2=inpaint_nans3(stacked_image2,1); % see Fex : https://fr.mathworks.com/matlabcentral/fileexchange/21214-inpainting-nan-elements-in-3-d
% slower :
% stacked_image2=inpaintn(stacked_image2); % see Fex : https://fr.mathworks.com/matlabcentral/fileexchange/27994-inpaint-over-missing-data-in-1-d-2-d-3-d-nd-arrays?s_tid=srchtitle
for ck = 1:m
figure
data2D = squeeze(stacked_image2(ck,:,:));
data2Dmean(ck) = mean(data2D,'all','omitnan');
imagesc(data2D);
caxis([mi ma]);
colorbar('vert');
end
% mean 2D interpolated data plot
figure
plot(x_axis,data2Dmean);
Mathieu NOE
on 15 May 2024
hello again
yes you can now save stacked_image2 as final data (as mat file)
I tried to find a solution for the automatic detection of cloudy image , based on the ratio of mean and std values
seems to work but may be tweaked in other situations
you need the attached function () to run it
new code :
load('ndvi.mat')
[m,n,p] = size(stacked_image);
mi = min(stacked_image,[],'all');
ma = max(stacked_image,[],'all');
x_axis = (1:m); % 12 months = 24 images
%% step1 : plot the raw data
for ck = 1:m
data2D = squeeze(stacked_image(ck,:,:));
% figure(ck)
% imagesc(data2D);
% caxis([mi ma]);
% colorbar('vert');
data2Dmean(ck) = mean(data2D,'all','omitnan');
data2Dstd(ck) = std(data2D,1,'all','omitnan');
end
% normalise mean and std values
data2Dmean = data2Dmean./max(data2Dmean);
data2Dstd = data2Dstd./max(data2Dstd);
r = abs(data2Dstd./data2Dmean); % ratio std over mean
% mean 2D raw data plot
N = m/4; % N must be choosen >= number of consecutive cloudy images (assumed) + 1
[down] = env_secant(x_axis,r, N, 'bottom');
% figure
% plot(x_axis,r,'-*',x_axis,down,'-*');
% selected indices (one year)
ind = find(r>1.5*down); % selected image to correct (down = threshold curve)
return
%% step 2 : identify images to be interpolated
% ind = [7 10 11 18];% selected image to correct :
stacked_image2 = stacked_image;
stacked_image2(ind,:,:) = NaN;
% now do interpolation on selected images
% faster :
stacked_image2=inpaint_nans3(stacked_image2,1); % see Fex : https://fr.mathworks.com/matlabcentral/fileexchange/21214-inpainting-nan-elements-in-3-d
% slower :
% stacked_image2=inpaintn(stacked_image2); % see Fex : https://fr.mathworks.com/matlabcentral/fileexchange/27994-inpaint-over-missing-data-in-1-d-2-d-3-d-nd-arrays?s_tid=srchtitle
for ck = 1:m
figure
data2D = squeeze(stacked_image2(ck,:,:));
data2Dmean(ck) = mean(data2D,'all','omitnan');
imagesc(data2D);
caxis([mi ma]);
colorbar('vert');
end
% mean 2D interpolated data plot
figure
plot(x_axis,data2Dmean);
gauri
on 15 May 2024
I have tried it and following errors have occured;
Error using assert
Parameter <y_data> has to be of vector type, holding finite numeric values!
Error in env_secant (line 25)
assert( isvector(y_data) && isnumeric(y_data) && all( isfinite( y_data ) ), ...
Error in ndvi_smooth (line 61)
[down] = env_secant(x_axis,r, N, 'bottom');
I request to please suggest me how to fix it.
Mathieu NOE
on 15 May 2024
hello again
did that occur with the same mat file ? (ndvi.mat) or is with another set of files ?
gauri
on 15 May 2024
This occured on a different set of files. I can save it in mat file and put on a google drive if required.
gauri
on 15 May 2024
I have put this another set of file (new_ndvi.mat) on following link;
I request you to please have a look on it.
Mathieu NOE
on 15 May 2024
hello
yes the problem comes from stacked_image is organized differently in the two provided mat file
ndvi.mat : stacked_image 24x1315x1153
new_ndvi.mat : stacked_image 1315x1153x24
so I had to change the way to index the data vs the image number , like
ndvi.mat : data2D = squeeze(stacked_image(ck,:,:));
new_ndvi.mat : data2D = squeeze(stacked_image(:,:,ck));
updated code :
(I have come back to te manual selection of images as my method is not yet robust enough)
clc
clearvars
close all
load('new_ndvi.mat') % OK
[m,n,p] = size(stacked_image);
mi = min(stacked_image,[],'all');
ma = max(stacked_image,[],'all');
x_axis = (1:p); % 12 months = 24 images
%% step1 : plot the raw data
for ck = 1:p
data2D = squeeze(stacked_image(:,:,ck));
figure(ck)
imagesc(data2D);
caxis([mi ma]);
colorbar('vert');
data2Dmean(ck) = mean(data2D,'all','omitnan');
data2Dstd(ck) = std(data2D,1,'all','omitnan');
end
%% step 2 : identify images to be interpolated
ind = [6];% selected image to correct :
% ind = [6 7 9 10];% selected image to correct :
stacked_image2 = stacked_image;
stacked_image2(:,:,ind) = NaN;
% now do interpolation on selected images
% faster :
stacked_image2=inpaint_nans3(stacked_image2,1); % see Fex : https://fr.mathworks.com/matlabcentral/fileexchange/21214-inpainting-nan-elements-in-3-d
% slower :
% stacked_image2=inpaintn(stacked_image2); % see Fex : https://fr.mathworks.com/matlabcentral/fileexchange/27994-inpaint-over-missing-data-in-1-d-2-d-3-d-nd-arrays?s_tid=srchtitle
for ck = 1:m
figure
data2D = squeeze(stacked_image2(:,:,ck));
data2Dmean(ck) = mean(data2D,'all','omitnan');
imagesc(data2D);
caxis([mi ma]);
colorbar('vert');
end
% mean 2D interpolated data plot
figure
plot(x_axis,data2Dmean);
gauri
on 16 May 2024
Thanks a lot for your kind cooperation. It worked well. I will keep the dimensions of stacked_image unchanged.
I appreciate your kind help.
Mathieu NOE
on 16 May 2024
as always, my pleasure !
gauri
on 17 May 2024
Thank you very much for your help. Further, once again I need your help to retrieve the data using shape file as follows;
mask = reshape(isinterior(polygon, lon(:), lat(:)), [length(lat), length(lon)]);
% Convert the logical mask to uint16 format
maskConverted = uint16(mask);
% Apply the converted mask to the raster
imgMasked = img .* maskConverted;
The size of imgMasked are same as that of img(5490 5490 7). However, it contains non zero data over shape file area and rest of the data are zeros only. I wanted to retrieve non zeros data out of imgMasked with the size of (1153 1315 7) as size of the shape file. I request you to please suggest me how to retrieve the desired data.
I would be highly obliged to you.
Mathieu NOE
on 17 May 2024
hello again
can you share imgMasked as a mat file ?
gauri
on 17 May 2024
Thank you very much for your generous support. This is the link for imgMasked.mat file;
Mathieu NOE
on 21 May 2024
hello
I believe the new size should be (1315 x 1153 x 7) and not (1153 x 1315 x 7) if you want to keep only the non zero elements
the code to crop the image is simple :
imgMasked2 = imgMasked(1:1315,1:1153,:);
gauri
on 21 May 2024
Thanks for your kind suggestions. Actually it worked but it is giving some zero values also in last few lines. Therefore, dimensions may be little bit different then 1315 x 1153 x 7. I request you to please suggest me how to figure out the actual dimensions of imgMasked non zero values.
I appreciate your kind help and cooperation.
Mathieu NOE
on 21 May 2024
try this instead :
load('imgMasked.mat')
[m,n,p] = size(imgMasked);
m1 = find(mean(imgMasked(:,:,1),1)<eps,1,'first') - 1;
m2 = find(mean(imgMasked(:,:,1),2)<eps,1,'first') - 1;
imgMasked2 = imgMasked(1:m2,1:m1,:);
gauri
on 21 May 2024
Thank you very much for your help. I am using it as follows
% Generate a mask by testing if the raster's geographic grid points are inside the polygon
mask = reshape(isinterior(polygon, lon(:), lat(:)), [length(lat), length(lon)]);
% Convert the logical mask to uint16 format
maskConverted = uint16(mask);
% Apply the converted mask to the raster
imgMasked = stacked_layer .* maskConverted;
[m, n, p] = size(imgMasked);
m1 = find(mean(imgMasked(:,:,1),1)<eps,1,'first') - 1;
m2 = find(mean(imgMasked(:,:,1),2)<eps,1,'first') - 1;
imgMasked2 = imgMasked(1:m2,1:m1,:);
disp(size(imgMasked2));
it is showing 0x0x7 dimensions. I request you to please suggest me how to fix it.
Mathieu NOE
on 22 May 2024
hello again
what are the values of m, n, p , m1 and m2 ?
gauri
on 22 May 2024
m = 5490 n = 5490 p = 7 m1 = 0 m2 = 0 These are the values I get.
Mathieu NOE
on 22 May 2024
funny
is it the exact same imgMasked data that I got from you or are you using another data set ?
if not, can you share again the data ?
gauri
on 22 May 2024
It is a different file but generated with same procedure. The link for this file is as follows;
Thank you so much for your help.
Mathieu NOE
on 22 May 2024
ok I understand now why I would not work , here a more robust approach - tested on both data sets
m1 = (mean(imgMasked(:,:,1),1)>eps);
m2 = (mean(imgMasked(:,:,1),2)>eps);
imgMasked2 = imgMasked(m2,m1,:);
gauri
on 22 May 2024
Thank you very much for your kind help. It worked very well for all files.
Mathieu NOE
on 22 May 2024
good news !
Aksh
on 13 Jun 2024
I have requested matlab community on my out of memory issue in my matlab code. I request you to please have a look on my question on the following link;
I would be highly obliged to you for your kind cooperation and help.
Categories
Find more on Coordinate Reference Systems in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!







