C语言 jni - 本机处理速度慢



切换到本机以获得更高的性能和处理速度,但不幸的是,我的应用程序太慢了。此外,加载高分辨率图像时,应用程序崩溃。

这是我的完整代码,供您告诉我如何改进它。

Java代码:

package com.example.invert;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
    ImageView imageView2;
    double[][][] imgArray;
    int w, h;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView2 = (ImageView) findViewById(R.id.imageView1);
        imageView2.setDrawingCacheEnabled(true);
        BitmapDrawable bitmapDrawable = (BitmapDrawable) imageView2
                .getDrawable();
        final Bitmap bitmap = bitmapDrawable.getBitmap();
        Button button = (Button) findViewById(R.id.button1);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                w = bitmap.getWidth();
                h = bitmap.getHeight();
                imgArray = new double[w][h][3];
                for (int i = 0; i < w; i++) {
                    for (int j = 0; j < h; j++) {
                        imgArray[i][j][0] = Color.red(bitmap.getPixel(i, j));
                        imgArray[i][j][1] = Color.green(bitmap.getPixel(i, j));
                        imgArray[i][j][2] = Color.blue(bitmap.getPixel(i, j));
                    }
                }
                imgArray = inv(imgArray, w, h);
                Bitmap newBitmap = Bitmap.createBitmap(w, h, bitmap.getConfig());
                for (int i = 0; i < w; i++) {
                    for (int j = 0; j < h; j++) {
                        newBitmap.setPixel(i, j, Color.rgb(
                                (int) (imgArray[i][j][0]),
                                (int) (imgArray[i][j][1]),
                                (int) (imgArray[i][j][2])));
                    }
                }
                imageView2.setImageBitmap(newBitmap);
            }
        });
    }
    static {
        System.loadLibrary("inv");
    }
    // internal, private
    public native double[][][] inv(double[][][] inputArr, int w, int h);
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

C 代码:

#include <jni.h>
#include <stdio.h>
#include<stddef.h>

JNIEXPORT jobjectArray JNICALL Java_com_example_invert_MainActivity_inv
  (JNIEnv *env, jobject obj, jobjectArray arr, jint w, jint h){
    double sum = 0;
    int i,j,k;
    double a[w][h][3];
     jsize dim1 = (*env)->GetArrayLength(env, arr);
       for (i=0; i<w; i++){
            jdoubleArray *line1 =   (*env)->GetObjectArrayElement(env, arr, i);
            int dim2 =       (*env)->GetArrayLength(env, line1);
            jdouble *pos1 = (*env)->GetDoubleArrayElements(env, line1, 0);
            for (j=0; j<h; j++){
                jdoubleArray *line2 =   (*env)->GetObjectArrayElement(env, line1, j);
                int dim3 =       (*env)->GetArrayLength(env, line2);
                jdouble *pos2 = (*env)->GetDoubleArrayElements(env, line2, 0);
                for (k=0; k<dim3; k++){
                        a[i][j][k]= pos2[k];
                    }
                (*env)->ReleaseDoubleArrayElements(env, line2, pos2, 0);
                (*env)->DeleteLocalRef(env, line2);
              }
            (*env)->ReleaseDoubleArrayElements(env, line1, pos1, 0);
            (*env)->DeleteLocalRef(env, line1);
       }


        jclass doubleArrayArrayClass = (*env)->FindClass(env,"[[D");
        jclass doubleArrayClass = (*env)->FindClass(env,"[D");

        jobjectArray ret  = (*env)->NewObjectArray(env,w, doubleArrayArrayClass, NULL);
        for( i = 0; i<w; i++){
            for( j = 0; j<h; j++){
                for( k = 0; k<3; k++){
                    a[i][j][k] = 255 - a[i][j][k];
                }
            }
        }
        for( i = 0; i<w; i++){
            jobjectArray dim2 = (*env)->NewObjectArray(env, w, doubleArrayClass, NULL);
            for( j = 0; j<h; j++) {
                jdoubleArray dim1 = (*env)->NewDoubleArray(env,h);
                jdouble tmp[3];
                for( k = 0; k<3; k++){
                    tmp[k] = a[i][j][k];
                }
                (*env)->SetDoubleArrayRegion(env,dim1 , 0, h, tmp);
                (*env)->SetObjectArrayElement(env, dim2, j, dim1);
                (*env)->DeleteLocalRef(env, dim1);
            }
            (*env)->SetObjectArrayElement(env,ret, i, dim2);
            (*env)->DeleteLocalRef(env,dim2);
        }
        return ret;
}

...在 Java 和 JNI 中,访问三维数组比访问相同大小的一维数组要慢得多。因此,我强烈建议使用 Java imgArray = new double[w*h*3] 创建并使用它。

这同样适用于输出数组。

此外,使用 SetDoubleArrayRegion() ,您可以引入一个额外的内存拷贝;更好的是,使用 double* cArray = GetDoubleArrayElements(env, jArray, 0) ,将值直接放入 cArray 中,然后使用 ReleaseDoubleArrayElements(env, jArray, cArray, 0) 将其发布到 Java 中。这个 0 表示对 cArray 的更改将在 Java 端的 jArray 中看到。

此外,Android NDK 通过 "android/bitmap.h" 提供从 C 语言直接访问 Bitmap 像素 #include。使用getPixel()setPixel()会增加巨大的开销。

在 C 端,最有可能的是,您的崩溃发生是因为堆栈上 a[w][h][3] 的大位图分配失败。堆栈不是用来容纳巨大的数据块。您必须在堆中分配数组。

如果您切换到 C++ 并使用 std::vector() 和其他有用的快捷方式,您的代码可能会更干净。

最新更新