2011-06-22 37 views
3

我正在使用Matlab/Octave imresize()函数重新采样给定的二维数组。我想了解imresize中使用的特定插值算法是如何工作的。在Matlab的imresize函数中用于插值的算法是什么?

(我在窗户上使用八度)

例如,

A = 1 2 
    3 4 

是一个2D数组。然后我用命令

b=imresize(a,2,'linear'); 

基本采样的行和列由2

输出是

1.0000 1.3333 1.6667 2.0000 
1.6667 2.0000 2.3333 2.6667 
2.3333 2.6667 3.0000 3.3333 
3.0000 3.3333 3.6667 4.0000 

我不明白这是如何线性插值工作。据说使用 bi 线性插值,但是它如何在边界处填充数据,以及它如何获得输出?

第二个例子: 对于

A = 

1 2 3 4 
5 6 7 8 
0 1 2 3 
1 2 3 4 

如何imresize(a,1.5,'linear')给下面的输出?

1.00000 1.60000 2.20000 2.80000 3.40000 4.00000 
3.40000 4.00000 4.60000 5.20000 5.80000 6.40000 
4.00000 4.60000 5.20000 5.80000 6.40000 7.00000 
1.00000 1.60000 2.20000 2.80000 3.40000 4.00000 
0.40000 1.00000 1.60000 2.20000 2.80000 3.40000 
1.00000 1.60000 2.20000 2.80000 3.40000 4.00000 

回答

0

正如您所看到的,在您的示例中,每个角点都是您的原始输入值之一。

中间值是通过在每个方向上的linear interpolation得出的。因此,例如,计算b(3,2)

  • b(1,2)b(1,1)b(1,4)的方式1/3。所以:

    b(1,2) = (1/3)*b(1,4) + (2/3)*b(1,1) 
    
  • b(4,2)b(4,1)b(4,4)的方式1/3。所以:

    b(4,2) = (1/3)*b(4,4) + (2/3)*b(4,1) 
    
  • b(3,2)b(1,2)b(4,2)的方式2/3。所以:

    b(3,2) = (2/3)*b(4,2) + (1/3)*b(1,2) 
    
+0

@Oli - 谢谢。我知道了。我假设,不同比例因子的权重计算将采用适当的值。即对于我的例子来说,权重为0.33,0.66,因为如果将2个样本内插到总共N个样本,则给定样本将被内插到总共4个样本,权重将是1 /(N-1),2 /( N-1)不是吗? – goldenmean

+0

@OliCharlesworth - 编辑的OP添加第二个例子,通过分数比例因子重新采样。在这种情况下,不清楚它如何编制其产出。你可以。上面的检查。 – goldenmean

+0

@Oli - 关于我在OP中添加的第二个示例的任何输入? – goldenmean

2

下面的代码演示了如何使用INTERP2执行bilinear interpolation

A = [1 2; 3 4]; 
SCALE = 2; 

xi = linspace(1,size(A,2),SCALE*size(A,2)); %# interpolated horizontal positions 
yi = linspace(1,size(A,1),SCALE*size(A,1)); %# interpolated vertical positions 
[X Y] = meshgrid(1:size(A,2),1:size(A,1)); %# pixels X-/Y-coords 
[XI YI] = meshgrid(xi,yi);     %# interpolated pixels X-/Y-coords 
B = interp2(X,Y,A, XI,YI, '*linear');  %# interp values at these positions 

结果与倍频码输出同意:

B = 
      1  1.3333  1.6667   2 
     1.6667   2  2.3333  2.6667 
     2.3333  2.6667   3  3.3333 
      3  3.3333  3.6667   4 

我应该提到我是IMRESIZE输出在MATLABOctave之间得到不同的结果。例如,这是当我执行的矩阵A=[1 2; 3 4]在MATLAB下面我得到什么:

>> B = imresize([1 2; 3 4], 2, 'bilinear') 
B = 
      1   1.25   1.75   2 
      1.5   1.75   2.25   2.5 
      2.5   2.75   3.25   3.5 
      3   3.25   3.75   4 

这表明MATLAB的实现做一些额外的......不幸的是,这并不容易阅读IMRESIZE源代码,尤其是因为在某些时候它调用了MEX编译的函数(没有可用的源代码表单)。作为一个附注,这个函数似乎还有一个旧版本:IMRESIZE_OLD(纯粹用m代码实现)。根据我的理解,它对图像进行某种仿射变换。也许有人更熟悉的技术可以摆脱一些关于这个问题光...

+0

我的猜测是Matlab在上采样之前在输入数据上运行高斯滤波器。八度不会这样做(虽然八度提到在帮助imresize,但不这样做,当我检查。 – goldenmean

+0

@goldenmean:这将解释的区别。无论如何,并回答您的原始问题,维基百科文章我用一个例子说明双线性插值过程.. – Amro

+1

我再看看IMRESIZE函数,请阅读我对这个问题的答案:http://stackoverflow.com/questions/7758078/resizing-in-matlab -w-different-filters/7759981#7759981 – Amro

1

我适应MATLAB对Java imresize功能:

import java.util.ArrayList; 
import java.util.List; 

public class MatlabResize { 
    private static final double TRIANGLE_KERNEL_WIDTH = 2; 

    public static double[][] resizeMatlab(double[][] data, int out_y, int out_x) { 
     double scale_x = ((double)out_x)/data[0].length; 
     double scale_y = ((double)out_y)/data.length; 

     double[][][] weights_indizes = contribution(data.length, out_y, scale_y, TRIANGLE_KERNEL_WIDTH); 
     double[][] weights = weights_indizes[0]; 
     double[][] indices = weights_indizes[1]; 

     final double[][] result = new double[out_y][data[0].length]; 
     double value = 0; 

     for (int p=0; p<result[0].length; p++) { 
      for (int i=0; i<weights.length; i++) { 
       value = 0; 

       for (int j=0; j<indices[0].length; j++) { 
        value += weights[i][j] * data[(int)indices[i][j]][p]; 
       } 

       result[i][p] = value; 
      } 
     } 

     weights_indizes = contribution(data[0].length, out_x, scale_x, TRIANGLE_KERNEL_WIDTH); 
     weights = weights_indizes[0]; 
     indices = weights_indizes[1]; 

     final double[][] result2 = new double[result.length][out_x]; 
     for (int p=0; p<result.length; p++) { 
      for (int i=0; i<weights.length; i++) { 
       value = 0; 

       for (int j=0; j<indices[0].length; j++) { 
        value += weights[i][j] * result[p][(int)indices[i][j]]; 
       } 

       result2[p][i] = value; 
      } 
     } 

     return result2; 
    } 

    public static double[][] resizeMatlab(double[][] data, double scale) { 
     int out_x = (int)Math.ceil(data[0].length * scale); 
     int out_y = (int)Math.ceil(data.length * scale); 

     double[][][] weights_indizes = contribution(data.length, out_y, scale, TRIANGLE_KERNEL_WIDTH); 
     double[][] weights = weights_indizes[0]; 
     double[][] indices = weights_indizes[1]; 

     final double[][] result = new double[out_y][data[0].length]; 
     double value = 0; 

     for (int p=0; p<result[0].length; p++) { 
      for (int i=0; i<weights.length; i++) { 
       value = 0; 

       for (int j=0; j<indices[0].length; j++) { 
        value += weights[i][j] * data[(int)indices[i][j]][p]; 
       } 

       result[i][p] = value; 
      } 
     } 

     weights_indizes = contribution(data[0].length, out_x, scale, TRIANGLE_KERNEL_WIDTH); 
     weights = weights_indizes[0]; 
     indices = weights_indizes[1]; 

     final double[][] result2 = new double[result.length][out_x]; 
     for (int p=0; p<result.length; p++) { 
      for (int i=0; i<weights.length; i++) { 
       value = 0; 

       for (int j=0; j<indices[0].length; j++) { 
        value += weights[i][j] * result[p][(int)indices[i][j]]; 
       } 

       result2[p][i] = value; 
      } 
     } 

     return result2; 
    } 


    private static double[][][] contribution(int length, int output_size, double scale, double kernel_width) { 
     if (scale < 1.0) { 
      kernel_width = kernel_width/scale; 
     } 

     final double[] x = new double[output_size]; 
     for (int i=0; i<x.length; i++) { 
      x[i] = i+1; 
     } 

     final double[] u = new double[output_size]; 
     for (int i=0; i<u.length; i++) { 
      u[i] = x[i]/scale + 0.5*(1 - 1/scale); 
     } 

     final double[] left = new double[output_size]; 
     for (int i=0; i<left.length; i++) { 
      left[i] = Math.floor(u[i] - kernel_width/2); 
     } 

     int P = (int)Math.ceil(kernel_width) + 2; 

     final double[][] indices = new double[left.length][P]; 
     for (int i=0; i<left.length; i++) { 
      for (int j=0; j<=P-1; j++) { 
       indices[i][j] = left[i] + j; 
      } 
     } 

     double[][] weights = new double[u.length][indices[0].length]; 
     for (int i=0; i<u.length; i++) { 
      for (int j=0; j<indices[i].length; j++) { 
       weights[i][j] = u[i] - indices[i][j]; 
      } 
     } 

     if (scale < 1.0) { 
      weights = triangleAntiAliasing(weights, scale); 
     } else { 
      weights = triangle(weights); 
     } 

     double[] sum = Matlab.sum(weights, 2); 
     for (int i=0; i<weights.length; i++) { 
      for (int j=0; j<weights[i].length; j++) { 
       weights[i][j] = weights[i][j]/sum[i]; 
      } 
     } 

     for (int i=0; i<indices.length; i++) { 
      for (int j=0; j<indices[i].length; j++) { 
       indices[i][j] = Math.min(Math.max(indices[i][j], 1.0), length); 
      } 
     } 

     sum = Matlab.sum(weights, 1); 
     int a = 0; 

     final List<Integer> list = new ArrayList<Integer>(); 
     for (int i=0; i<sum.length; i++) { 
      if (sum[i] != 0.0) { 
       a++; 
       list.add(i); 
      } 
     } 

     final double[][][] result = new double[2][weights.length][a]; 
     for (int i=0; i<weights.length; i++) { 
      for (int j=0; j<list.size(); j++) { 
       result[0][i][j] = weights[i][list.get(j)]; 
      } 
     } 
     for (int i=0; i<indices.length; i++) { 
      for (int j=0; j<list.size(); j++) { 
       result[1][i][j] = indices[i][list.get(j)]-1; //java indices start by 0 and not by 1 
      } 
     } 

     return result; 
    } 

    private static double[][] triangle(final double[][] x) { 
     for (int i=0; i<x.length; i++) { 
      for (int j=0; j<x[i].length; j++) { 
       if (-1.0 <= x[i][j] && x[i][j] < 0.0) { 
        x[i][j] = x[i][j] + 1; 
       } else if (0.0 <= x[i][j] && x[i][j] < 1.0) { 
        x[i][j] = 1 - x[i][j]; 
       } else { 
        x[i][j] = 0; 
       } 
      } 
     } 

     return x; 
    } 

    private static double[][] triangleAntiAliasing(final double[][] x, final double scale) { 
     for (int i=0; i<x.length; i++) { 
      for (int j=0; j<x[i].length; j++) { 
       x[i][j] = x[i][j] * scale; 
      } 
     } 

     for (int i=0; i<x.length; i++) { 
      for (int j=0; j<x[i].length; j++) { 
       if (-1.0 <= x[i][j] && x[i][j] < 0.0) { 
        x[i][j] = x[i][j] + 1; 
       } else if (0.0 <= x[i][j] && x[i][j] < 1.0) { 
        x[i][j] = 1 - x[i][j]; 
       } else { 
        x[i][j] = 0; 
       } 
      } 
     } 

     for (int i=0; i<x.length; i++) { 
      for (int j=0; j<x[i].length; j++) { 
       x[i][j] = x[i][j] * scale; 
      } 
     } 

     return x; 
    } 
} 
+0

那么你是说你的代码和MATLAB'imresize'代码是一样的吗?你是否反向设计了Amro提到的MEX编译函数?或者你只是总体上实现了一个类似的功能,而不验证它在不同的角落情况下产生相同的结果? –

+2

嗯..等价.. :)我试图理解'imresize'函数在MATLAB和将它移植到JAVA。 (这个函数的源代码是可读的)。有了这个功能(对于600x600矩阵调整到192x192),就像在MATLAB中一样。但是我没有用单元测试来测试它。 – lhlmgr

相关问题