2011-06-22 32 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

相關問題