降低双线性插值的时间复杂度

时间:2016-04-14 11:26:41

标签: java android algorithm opencv time-complexity

我在我的Android应用程序中使用双线性插值。它运行完美,但需要花费大量时间才能得到结果。

我在xi = 259,920时测试它,yi也是259,920。回应的时间是:Galaxy Note 4需要3秒,                           和HTC One M8大约需要8秒!那么我可以改变或使用什么来减少时间?!

我用于双线性插值的代码:

public static double[] BiInterp(Mat z, ArrayList < Double > xi, ArrayList < Double > yi) {
    // Declare matrix indeces
    int xi_i, yi_i;
    // Initialize output vector
    double zi[] = new double[xi.size()];
    double s00, s01, s10, s11;
    for (int i = 0; i < xi.size(); i++) { // Note: xi.length = yi.length !
        xi_i = xi.get(i).intValue(); // X index without round
        yi_i = yi.get(i).intValue(); // Y index without round
        if (xi_i < z.rows() - 1 && yi_i < z.cols() - 1 && xi_i >= 0 && yi_i >= 0) {
            // Four neighbors of sample pixel
                s00 = z.get(xi_i,yi_i)[0]; s01 = z.get(xi_i,yi_i + 1)[0];
                s10 = z.get(xi_i + 1,yi_i)[0];s11 = z.get(xi_i + 1,yi_i + 1)[0];

            int neighbor_no = 4; // As bilinear interpolation take 4 neighbors
            double A[][] = new double[neighbor_no][neighbor_no];

            A[0][0]=xi_i; A[0][1]=yi_i; A[0][2]=xi_i*yi_i; A[0][3]=1;
            A[1][0]=xi_i; A[1][1]=yi_i+1; A[1][2]=xi_i*(yi_i+1); A[1][3]=1;
            A[2][0]=xi_i+1; A[2][1]=yi_i; A[2][2]=(xi_i+1)*yi_i; A[2][3]=1;
            A[3][0]=xi_i+1; A[3][1]=yi_i+1; A[3][2]=(xi_i+1)*(yi_i+1); A[3][3]=1;

            GaussianElimination solveE = new GaussianElimination();
            double b[] = {s00,s01,s10,s11};
            double x[] = solveE.solve(A, b);
            zi[i] = xi.get(i)*x[0] + yi.get(i)*x[1] + xi.get(i)*yi.get(i)*x[2] + x[3];
        }
    }
    return zi;
}

我用高斯消元法求解4未知

的方程
private static final double EPSILON = 1e-10;

// Gaussian elimination with partial pivoting
public static double[] solve(double[][] A, double[] b) {
    int N = b.length;

    for (int p = 0; p < N; p++) {

        // find pivot row and swap
        int max = p;
        for (int i = p + 1; i < N; i++) {
            if (Math.abs(A[i][p]) > Math.abs(A[max][p])) {
                max = i;
            }
        }
        double[] temp = A[p];
        A[p] = A[max];
        A[max] = temp;
        double t = b[p];
        b[p] = b[max];
        b[max] = t;

        // singular or nearly singular
        if (Math.abs(A[p][p]) <= EPSILON) {
            throw new RuntimeException("Matrix is singular or nearly singular");
        }

        // pivot within A and b
        for (int i = p + 1; i < N; i++) {
            double alpha = A[i][p] / A[p][p];
            b[i] -= alpha * b[p];
            for (int j = p; j < N; j++) {
                A[i][j] -= alpha * A[p][j];
            }
        }
    }

    // back substitution
    double[] x = new double[N];
    for (int i = N - 1; i >= 0; i--) {
        double sum = 0.0;
        for (int j = i + 1; j < N; j++) {
            sum += A[i][j] * x[j];
        }
        x[i] = (b[i] - sum) / A[i][i];
    }
    return x;
}

正如您在双线性代码中看到的那样,我立即从Mat对象中获取像素强度。然而,当我使用矩阵时,它花费的时间要少得多,例如注意4需要1秒。

但是从Mat图像转换为矩阵需要4秒。所以我更喜欢使用Mat。

1 个答案:

答案 0 :(得分:1)

这是一个更简单的双线性插值算法:

  • 找到yi的小数部分并用它在s00和s01之间插值以找到s0,并在s10和s11之间找到s1
  • 找到xi的小数部分并用它在s0和s1之间进行插值以找到zi

基本上你将它分解为三个简单的线性插值。您可以将其可视化为H形状。首先,向下插入H的左右柱,以获得每个值的中间值。然后沿横梁进行插值,得到中间的最终值。

代码将是这样的:

    xi_i = xi.get(i).intValue(); // X index without round
    yi_i = yi.get(i).intValue(); // Y index without round
    if (xi_i < z.rows() - 1 && yi_i < z.cols() - 1 && xi_i >= 0 && yi_i >= 0) {
        // Four neighbors of sample pixel
        s00 = z.get(xi_i,yi_i)[0]; s01 = z.get(xi_i,yi_i + 1)[0];
        s10 = z.get(xi_i + 1,yi_i)[0];s11 = z.get(xi_i + 1,yi_i + 1)[0];

        // find fractional part of yi:
        double yi_frac = yi.get(i) - (double)yi_i;

        // interpolate between s00 and s01 to find s0:
        double s0 = s00 + ((s01 - s00) * yi_frac);
        // interpolate between s10 and s11 to find s1:
        double s1 = s10 + ((s11 - s10) * yi_frac);

        // find fractional part of xi:
        double xi_frac = xi.get(i) - (double)xi_i;

        // interpolate between s0 and s1 to find zi:
        zi[i] =  s0 + ((s1 - s0) * xi_frac);
    }

你也可以通过使用定点整数而不是双精度来加快整个过程(以牺牲准确性为代价)。