最近邻插值如何在MATLAB中工作?

时间:2013-09-20 03:20:48

标签: matlab image-processing interpolation image-resizing nearest-neighbor

我想了解最近邻插值在MATLAB中的工作原理。我有输入数据:

A = [1 4 7 4 3 6]     % 6 digit vector

我使用以下MATLAB代码:

B = imresize(A,[1 9],'nearest');

我得到以下结果:

[1,4,4,7,4,4,3,6,6]

手工解决,我得到了这个结果:

[1 4 4 7 4 4 3 3 6]
你能指导我吗?我在某个地方出错了吗?

3 个答案:

答案 0 :(得分:3)

如果使用interp1应用常规插值,它将为您提供手动计算的结果:

>> 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

前段时间,我查看了IMRESIZE的源代码,试图了解它是如何工作的。 See this post摘要。在某些时候,代码将调用私有MEX函数(没有相应的源代码可用),但注释足以理解实现。

对于它的价值,还有一个函数imresize_old,它提供imresize的较早实现(在版本R2006b及更早版本中使用)。它给出了另一个不同的结果:

>> 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

it was previously observed MATLABOctave之间的实施在某些情况下也有所不同。


编辑:

interpolation

正如您所指出的,在某些情况下,在使用interp1时,您必须注意浮点限制。因此,我们可以通过选择x值在[0,1]范围之间或更稳定的范围(如[1,numel(A)])来进行插值。由于边缘情况下的舍入误差,这可能会产生不同的结果。

例如,比较以下两个代码:

% 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])

针对:

% 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])

这是输出格式很好:

--------------------------------------------------------
       [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 |
--------------------------------------------------------

因此,您可以看到在[0,1]范围内工作时,某些数字在双精度中无法准确表示。因此,假定在中间[0.2,0.4]的0.3由于舍入误差而变得更接近0.2的下端而不是0.4。而在另一方面,2.5恰好位于[2,3]的中间(所有数字都精确表示),并使用最近邻居分配给上端3。

另请注意,colonlinspace有时会产生不同的输出:

>> (0:0.1:1)' - linspace(0,1,11)'
ans =
            0
            0
            0
   5.5511e-17
            0
            0
            0
            0
            0
            0
            0

答案 1 :(得分:1)

NN是最简单的插值形式。它具有以下配方:使用最近的样本位置处的值。 MATLAB中的NN插值具有计算效率,但如果您需要更高的精度,我建议您使用双线性或双三次插值。您也可以检查 interp1()

此处提供了一个示例说明:http://www.mathworks.com/help/vision/ug/interpolation-methods.html

答案 2 :(得分:0)

我没有参考,所以我建议您使用imresize对其他示例进行测试,但我可以恢复Mat; ab的值是这样的。

假设A代表y值,A中元素的位置代表x值。所以现在

n = length(A);
N = 9;

x = 1:n %// i.e. 1:6

现在我们需要找到插值位置,即xi点。我会这样做的:

xi = round((1:N)/N)*n

给出了

xi =

   1   1   2   3   3   4   5   5   6

会产生yi

yi = A(xi)

yi =

   1   1   4   7   7   4   3   3   6

这与你和Matlab的答案都有所不同(你是怎么得到的?)

然后我尝试了:

xi = round(((0:N-1)/N)*n)+1
yi = A(xi)

这同样有意义,让我得到了Matlab的

结果
yi =

   1   4   4   7   4   4   3   6   6

所以我猜他们是怎么做到的。但我没有imresize来测试其他案例