jni - Slow processing in native

ぃ、小莉子 提交于 2019-12-13 10:20:01

问题


Switching to native to get more performance and processing speed, but unfortunately, my app is too slow. Also, when loading high-resolution images, the app crashes.

Here is my full code for you to tell me how to improve it.

java code:

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 code:

#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;
}

回答1:


… access to 3-dimensional array is much slower both in Java and JNI than access to 1-dimensional array of same size. Therefore I would strongly recommend to create in Java imgArray = new double[w*h*3] and work with it.

Same applies to the output array.

Also, using SetDoubleArrayRegion(), you introduce an extra memcopy; better, use double* cArray = GetDoubleArrayElements(env, jArray, 0), put the values directly into cArray, and release it to Java with ReleaseDoubleArrayElements(env, jArray, cArray, 0). This 0 means that the changes to cArray will be seen in jArray on the Java side.

Also, Android NDK provides direct access to Bitmap pixels from C via #include "android/bitmap.h". Working with getPixel() and setPixel() adds huge overhead.

On the C side, most likely, your crash happens because for a big bitmap allocation of a[w][h][3] on stack fails. Stack is not intended to hold huge data chunks. You must allocate your array in the heap.

Your code will probably be much cleaner if you switch to C++ and use std::vector() and other helpful shortcuts.



来源:https://stackoverflow.com/questions/35529437/jni-slow-processing-in-native

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!