JNI - 在本地处理缓慢 [英] jni - Slow processing in native

查看:134
本文介绍了JNI - 在本地处理缓慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

下面是我的全code你来告诉我如何改进它。

Java的code:

 包com.example.invert;进口android.graphics.Bitmap;
进口android.graphics.BitmapFactory;
进口android.graphics.Color;
进口android.graphics.drawable.BitmapDrawable;
进口android.os.Bundle;
进口android.support.v7.app.ActionBarActivity;
进口android.util.Log;
进口android.view.Menu;
进口android.view.MenuItem;
进口android.view.View;
进口android.view.View.OnClickListener;
进口android.widget.Button;
进口android.widget.ImageView;
进口android.widget.Toast;公共类MainActivity扩展ActionBarActivity {
    ImageView的imageView2;
    双[] [] [] imgArray;
    INT W,H;    @覆盖
    保护无效的onCreate(捆绑savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_main);
        imageView2 =(ImageView的)findViewById(R.id.imageView1);
        imageView2.setDrawingCacheEnabled(真);
        BitmapDrawable bitmapDrawable =(BitmapDrawable)imageView2
                .getDrawable();
        最终位图的位图= bitmapDrawable.getBitmap();
        Button按钮=(按钮)findViewById(R.id.button1);        button.setOnClickListener(新OnClickListener(){            @覆盖
            公共无效的onClick(视图v){                W = bitmap.getWidth();
                H = bitmap.getHeight();
                imgArray =新双[W] [H] [3];                的for(int i = 0; I<瓦;我++){
                    对于(INT J = 0; J< 1H; 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);
                位图newBitmap = Bitmap.createBitmap(W,H,bitmap.getConfig());
                的for(int i = 0; I<瓦;我++){
                    对于(INT J = 0; J< 1H; J ++){
                        newBitmap.setPixel(I,J,Color.rgb(
                                (中间体)(imgArray [I] [j]的[0]),
                                (中间体)(imgArray [I] [j]的[1]),
                                (中间体)(imgArray [I] [j]的[2])));
                    }
                }                imageView2.setImageBitmap(newBitmap);            }
        });    }    静态的 {
        的System.loadLibrary(INV);
    }    //内部私有
    公共本土双重[] [] [] INV(双[] [] [] inputArr,INT W,INT H);    @覆盖
    公共布尔onCreateOptionsMenu(菜单菜单){
        //充气菜单;如果是present这增加了项目操作栏。
        。getMenuInflater()膨胀(R.menu.main,菜单);
        返回true;
    }}

C code:

 的#include< jni.h>
#包括LT&;&stdio.h中GT;
#包括LT&;&STDDEF.H GT;
JNIEXPORT jobjectArray JNICALL Java_com_example_invert_MainActivity_inv
  (JNIEnv的* ENV,jobject OBJ,jobjectArray ARR,jint W,jint高){
    双总和= 0;
    INT I,J,K;
    双一[W] [H] [3];
     jsize DIM1 =(* ENV) - GT; GetArrayLength(ENV,ARR);       对于(i = 0; I<瓦;我++){            jdoubleArray *行1 =(* ENV) - GT; GetObjectArrayElement(ENV,编曲,我);
            INT DIM2 =(* ENV) - GT; GetArrayLength(ENV,一号线);
            jdouble * POS1 =(* ENV) - > GetDoubleArrayElements(ENV,行1,0);            为(J = 0; J&下; 1H; J ++){
                jdoubleArray * 2号线=(* ENV) - GT; GetObjectArrayElement(ENV,一号线,J);
                INT为dim3 =(* ENV) - GT; GetArrayLength(ENV,2号线);
                jdouble * POS2 =(* ENV) - > GetDoubleArrayElements(ENV,LINE2,0);                对于(K = 0; K<为dim3; k ++){
                        一个由[i] [j]的[K] = POS2 [K];
                    }
                (* ENV) - > ReleaseDoubleArrayElements(ENV,LINE2,POS2,0);
                (* ENV) - GT; DeleteLocalRef(ENV,2号线);
              }            (* ENV) - GT; ReleaseDoubleArrayElements(ENV,一号线,POS1,0);
            (* ENV) - GT; DeleteLocalRef(ENV,一号线);
       }
        JCLASS doubleArrayArrayClass =(* ENV) - GT;的findClass(ENV[D);
        JCLASS doubleArrayClass =(* ENV) - GT;的findClass(ENV[D);
        jobjectArray RET =(* ENV) - > NewObjectArray(ENV,W,doubleArrayArrayClass,NULL);        对于(i = 0; I<瓦;我++){
            为(J = 0; J&下; 1H; J ++){
                为(K = 0; k 3;; k ++){                    一个由[i] [j]的[K] = 255 - 一个由[i] [j]的[K];
                }
            }
        }        对于(i = 0; I<瓦;我++){            jobjectArray DIM2 =(* ENV) - > NewObjectArray(ENV,W,doubleArrayClass,NULL);
            为(J = 0; J&下; 1H; J ++){                jdoubleArray DIM1 =(* ENV) - GT; NewDoubleArray(ENV,H);
                jdouble TMP [3];
                为(K = 0; k 3;; k ++){
                    TMP [K] = a [i] [j]的[K];
                }
                (* ENV) - GT; SetDoubleArrayRegion(ENV,DIM1,0,H,TMP);
                (* ENV) - GT; SetObjectArrayElement(ENV,DIM2,J,DIM1);
                (* ENV) - GT; DeleteLocalRef(ENV,DIM1);
            }
            (* ENV) - GT; SetObjectArrayElement(ENV,RET,我,DIM2);
            (* ENV) - GT; DeleteLocalRef(ENV,DIM2);
        }
        返回RET;
}


解决方案

... 以3维数组访问是多少无论是在Java和JNI比获得相同大小的1维阵列慢。因此,我强烈建议在Java创建 imgArray =新的双[W * H * 3] 并使用它。

同样适用于输出阵列

此外,使用 SetDoubleArrayRegion(),你介绍一个额外的存储器复制;好,使用双* CARRAY = GetDoubleArrayElements(ENV,jArray,0),把价值观直接进入 CARRAY ,并将其与<释放到Java code> ReleaseDoubleArrayElements(ENV,jArray,CARRAY,0)。这 0 意味着更改 CARRAY 将在 jArray 可以看到在Java端。

另外,Android的NDK提供了从C通过的#include机器人为位图像素直接访问/ bitmap.h。与 getPixel工作()与setPixel()增加巨大的开销。

在C面,最有可能的,你的崩溃是因为对于 [W] [H] [3] 在堆栈失败一大位图分配。堆栈并不打算持有庞大的数据块。你必须分配在堆中的数组。

您code可能会是干净多了,如果你切换到C ++和使用的std ::向量()和其他有用的快捷键。

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

解决方案

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.

这篇关于JNI - 在本地处理缓慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆