If you apply regular interpolation using interp1
, it will give you the result that you calculated manually:
>> N = 9; >> B = interp1(linspace(0,1,numel(A)), A, linspace(0,1,N), 'nearest') B = 1 4 4 7 4 4 3 3 6
Some time ago I looked at the source code of IMRESIZE, trying to understand how this works. See this post for a summary. At some point, the code will call a private MEX function (without the corresponding source code), but there are enough comments to understand the implementation.
For what it's worth, there is also the imresize_old
function, which provides an older imresize
implementation (used in R2006b and earlier). This gave another different result:
>> B = imresize(A, [1 N], 'nearest') B = 1 4 4 7 4 4 3 6 6 >> B = imresize_old(A, [1 N], 'nearest') B = 1 4 4 7 7 4 3 6 6
What was previously noted , the implementation between MATLAB and Octave was also different in some cases.
EDIT:
As you noted, in some cases you should be aware of floating point restrictions when working with interp1
. Thus, we could interpolate by choosing x-numbers between the range [0,1]
or a more stable range, for example [1,numel(A)]
. Due to rounding errors in edge cases, this can give different results.
For example, compare the two codes below:
% interpolation in [0,1] N = 11; y = [1 4 7 4 3 6]; x = linspace(0,1,numel(y)); xi = linspace(0,1,N); yi = interp1(x, y, xi, 'nearest'); % print numbers with extended precision fprintf('%.17f %g\n',[x;y]) fprintf('%.17f %g\n',[xi;yi])
vs
% interpolation in [1,k] N = 11; y = [1 4 7 4 3 6]; x = 1:numel(y); xi = linspace(1,numel(y),N); yi = interp1(x, y, xi, 'nearest'); % print numbers with extended precision fprintf('%.17f %g\n',[x;y]) fprintf('%.17f %g\n',[xi;yi])
Here is a result that is well formatted:
-------------------------------------------------------- [0,1] RANGE | [1,k] RANGE -------------------------------------------------------- xi yi | xi yi -------------------------------------------------------- 0.00000000000000000 1 | 1.00000000000000000 1 | 0.20000000000000001 4 | 2.00000000000000000 4 | 0.40000000000000002 7 | 3.00000000000000000 7 | 0.59999999999999998 4 | 4.00000000000000000 4 | INPUT 0.80000000000000004 3 | 5.00000000000000000 3 | 1.00000000000000000 6 | 6.00000000000000000 6 | -------------------------------------------------------- 0.00000000000000000 1 | 1.00000000000000000 1 | 0.10000000000000001 4 | 1.50000000000000000 4 | 0.20000000000000001 4 | 2.00000000000000000 4 | 0.29999999999999999 4 | 2.50000000000000000 7 | 0.40000000000000002 7 | 3.00000000000000000 7 | 0.50000000000000000 4 | 3.50000000000000000 4 | OUTPUT 0.59999999999999998 4 | 4.00000000000000000 4 | 0.69999999999999996 4 | 4.50000000000000000 3 | 0.80000000000000004 3 | 5.00000000000000000 3 | 0.90000000000000002 6 | 5.50000000000000000 6 | 1.00000000000000000 6 | 6.00000000000000000 6 | --------------------------------------------------------
So, you can see that some numbers are not accurately represented in double precision when working in the range [0,1]. Thus, 0.3, which is supposedly located in the middle [0.2, 0.4], is closer to the lower end 0.2 0.2 due to rounding error. While on the other side 2.5 is exactly in the middle of [2,3] (all numbers are accurately represented) and assigned to the upper end of 3 with the help of the nearest neighbor.
Also keep in mind that colon
and linspace
can sometimes produce different results:
>> (0:0.1:1)' - linspace(0,1,11)' ans = 0 0 0 5.5511e-17 0 0 0 0 0 0 0