应用程序使用大型数组 "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];
}
}
我正在编写代码,使用 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];
}
}