应用程序使用大型数组 "stops working",但仍继续将日志消息打印到 AndroidStudio

App working with large arrays "stops working", but still continues to print Log messages to AndroidStudio

我正在编写代码,使用 4 个用户选择的点对图像执行投影变换 (https://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript)。

在这样做时,我必须使用非常大的数组(300k+ 索引)。当我 运行 它时,我的 phone 屏幕变黑,几秒钟后显示消息“已停止工作。”但是,它继续向我的 AndroidStudio logcat 打印日志消息,其中包含有关它正在处理的数组的信息,让我知道它仍在 运行ning.

我对计算效率不是很了解,所以我可能会犯一些涉及矩阵操作的致命错误。它中断的代码部分是 transform() 的最后部分,logcat 打印 "rounded" 值,而 phone 显示 "stopped working" 消息。

我已经包含了相关代码。对我做错的任何事情(相关或不相关)的任何建议都表示赞赏,因为这是我第一次体验 Android 开发。

我或多或少只是遵循 math.stackexchange link 中提供的转换。

public class projTransform extends Activity{

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_proj_transform);

    Intent parent_intent = getIntent();
    Uri imgUri = parent_intent.getData();
    pointArray = parent_intent.getDoubleArrayExtra("points");
    //dimens[0-3]: width, height, minX, minY
    dimens = parent_intent.getIntArrayExtra("dimens");
    transform(imgUri,pointArray, dimens);
}
//A*B = C
private static double[][] mMult(double[][] A, double[][] B){
    int mA = A.length;
    int nA = A[0].length;
    int mB = B.length;
    int nB = B[0].length;
    if (nA != mB) throw new RuntimeException("Illegal matrix dimensions.");
    double[][] C = new double[mA][nB];
        for (int i = 0; i < mA; i++)
        for (int j = 0; j < nB; j++)
            for (int k = 0; k < nA; k++)
                C[i][j] += A[i][k] * B[k][j];
    return C;
}
//A*x = y
private static double[] mMult(double[][] A, double[] x){
    int m = A.length;
    int n = A[0].length;
    if (x.length != n) throw new RuntimeException("Illegal matrix dimensions.");
    double[] y = new double[m];
    for (int i = 0; i < m; i++)
        for (int j = 0; j < n; j++)
            y[i] += A[i][j] * x[j];
    return y;
}
//https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices
//A^(-1)
private static double[][] mInvert3x3(double[][] X){
    double[][] Y = new double[3][3];
    double A,B,C,D,E,F,G,H,I,detX;
    A =   X[1][1]*X[2][2] - X[1][2]*X[2][1];
    B = -(X[1][0]*X[2][2] - X[1][2]*X[2][0]);
    C =   X[1][0]*X[2][1] - X[1][1]*X[2][0];
    D = -(X[0][1]*X[2][2] - X[0][2]*X[2][1]);
    E =   X[0][0]*X[2][2] - X[0][2]*X[2][0];
    F = -(X[0][0]*X[2][1] - X[0][1]*X[2][0]);
    G =   X[0][1]*X[1][2] - X[0][2]*X[1][1];
    H = -(X[0][0]*X[1][2] - X[0][2]*X[1][0]);
    I =   X[0][0]*X[1][1] - X[0][1]*X[1][0];
    detX = X[0][0]*A + X[0][1]*B + X[0][2]*C;

    Y[0][0] = A/detX;
    Y[1][0] = B/detX;
    Y[2][0] = C/detX;
    Y[0][1] = D/detX;
    Y[1][1] = E/detX;
    Y[2][1] = F/detX;
    Y[0][2] = G/detX;
    Y[1][2] = H/detX;
    Y[2][2] = I/detX;

    return Y;
}

private void transform(Uri data, double[] sourceArray, int[] dimens){

    if (data != null) {
        try {
            InputStream imgStream = getContentResolver().openInputStream(data);
            tempBmp = BitmapFactory.decodeStream(imgStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        Matrix matrix = new Matrix();
        matrix.postRotate(90);
        Bitmap rotatedbmp = Bitmap.createBitmap(tempBmp, 0, 0, tempBmp.getWidth(), tempBmp.getHeight(), matrix, true);

        crop = new int[dimens[0] * dimens[1]];
        rotatedbmp.getPixels(crop, 0, dimens[0], dimens[2], dimens[3], dimens[0], dimens[1]);

        //map for original bmp
        double[][] sourceMap = tMap(sourceArray);
        Log.e("sourceMap",toString(sourceMap));

        //map for transformed bmp
        double[] destArray = new double[] {0,0,0,destHeight,destWidth,0,destHeight,destWidth};
        double[][] destMap = tMap(destArray);
        Log.e("destMap",toString(destMap));

        // C = B*[A^(-1)]
        double[][] finalMap = mMult(sourceMap, mInvert3x3(destMap));

        Log.e("width", String.valueOf(dimens[0]));

        int[] destPixels = new int[destHeight*destWidth];
        int[] temp;
        for(int i=0; i<destHeight-1; i++){
            for(int j=0; j<destWidth-1; j++){
                temp = pixelMap(finalMap,i,j);
                Log.e("rounded", String.valueOf(temp[0]) + ", " + String.valueOf(temp[1]));
                destPixels[(i*destWidth)+j] = crop[(temp[0]*dimens[0]) + temp[1]];
            }
        }
        display(destPixels, destWidth, destHeight);
    }
}

//produces mapping matrix given corners
//A,B in SE post
private double[][] tMap(double[] pointArray){
    double[][] tempArray = new double[3][3];
    tempArray[0][0] = pointArray[0];
    tempArray[1][0] = pointArray[1];
    tempArray[0][1] = pointArray[2];
    tempArray[1][1] = pointArray[3];
    tempArray[0][2] = pointArray[4];
    tempArray[1][2] = pointArray[5];
    for(int i=0; i<3; i++){
        tempArray[2][i] = 1;
    }
    //Log.e("tempArray",toString(tempArray));

    double[] tempVector = new double[] {pointArray[6], pointArray[7], 1};

    //Log.e("tempVector",toString(tempVector));

    double[][] inverted = mInvert3x3(tempArray);

    //Log.e("inverted",toString(inverted));

    double[] coef = mMult(inverted, tempVector);

    //Log.e("coef",toString(coef));

    double[][] tran = new double[3][3];

    for(int i=0; i<3; i++){
        for (int j=0; j<3; j++){
            tran[i][j] = tempArray[i][j]*coef[j];
        }
    }
    return tran;
}

private int[] pixelMap(double[][] map, double x, double y){
    double[] tempVector = new double[] {x,y,1};
    double[] primeVector = mMult(map,tempVector);
    return new int[] {(int) Math.round(primeVector[0]/primeVector[2]), (int) Math.round(primeVector[1]/primeVector[2])};
}

你不需要除以行列式;伴随而不是逆就足够了。除此之外,您正在创建很多对象。

紧密循环是围绕 pixelMap 调用的两个嵌套循环。尝试在那里内联 pixelMap,并尽量避免创建新数组。对所有单独的坐标使用单独的变量。使用您知道尺寸的事实。

x = finalMap[0][0]*i + finalMap[0][1]*j + finalMap[0][2];

等等。如果您愿意,可以将 finalMap 移动到一组 9 个局部变量中以帮助优化器。还要禁用日志记录行,因为缓存和传输那么多日志输出会占用大量资源。开始循环时执行一个日志行,完成后执行另一个日志行。最后,循环看起来像这样:

    for(int i=0; i<destHeight-1; i++){
        for(int j=0; j<destWidth-1; j++){
            double x = finalMap00*i + finalMap01*j + finalMap02;
            double y = finalMap10*i + finalMap11*j + finalMap12;
            double z = finalMap20*i + finalMap21*j + finalMap22;
            int xi = (int)Math.round(x/z), yi = (int)Math.round(y/z);
            destPixels[(i*destWidth)+j] = crop[(xi*srcWidth) + yi];
        }
    }