2016-02-20 5 views
-1

Переключение на native, чтобы повысить производительность и скорость обработки, но, к сожалению, мое приложение слишком медленно. Кроме того, при загрузке изображений с высоким разрешением приложение выходит из строя.jni - Медленная обработка в native

Вот мой полный код для вас, чтобы рассказать мне, как его улучшить.

код 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; 
    } 

} 

код С:

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

Вы должны уточнить, что происходит, когда приложение «сбой». Получают ли сообщения трассировки или ошибки. Что касается медленного, вы должны узнать, как профилировать свой код, чтобы узнать, где он занимает больше всего времени. –

+0

[* Попробуйте это. *] (Http://stackoverflow.com/a/378024/23771) Это не вопрос выяснить *, где * это занимает больше всего времени, но * почему *. –

ответ

1

доступ к 3-мерный массив гораздо медленнее, как в Java и JNI, чем доступ к 1-мерного массива одинакового размера. Поэтому я настоятельно рекомендую создать на Java imgArray = new double[w*h*3] и работать с ним.

То же самое относится к выходному массиву.

Также, используя SetDoubleArrayRegion(), вы вводите дополнительную memcopy; лучше, используйте double* cArray = GetDoubleArrayElements(env, jArray, 0), поместите значения непосредственно в cArray и отпустите его на Java с ReleaseDoubleArrayElements(env, jArray, cArray, 0). Этот означает, что изменения в cArray будут отображаться в jArray со стороны Java.

Кроме того, Android NDK обеспечивает прямой доступ к растровым пикселям от C через #include "android/bitmap.h". Работа с getPixel() и setPixel() добавляет огромные накладные расходы.

На стороне C, скорее всего, ваш сбой происходит из-за большого выделения растрового изображения a [w] [h] [3] на стек сбоя. Стек не предназначен для хранения огромных блоков данных. Вы должны выделить свой массив в куче.

Ваш код, вероятно, будет намного чище, если вы перейдете на C++ и используйте std :: vector() и другие полезные ярлыки.

+0

Я писал эти советы раньше; вы попробовали их и обнаружили, что они не дают вам ожидаемого повышения? Или вы не понимали, как им следовать, и нужно больше руководства? –

+0

1-для первого совета, я бы предпочел сохранить шаблон [] [] [], потому что, я собираюсь реализовать алгоритм, требующий много 3D-циклов ... 2- Я не понял вашу мысль: вы можете объяснить Больше? 3- Для bitmap.h я не знаю, как извлечь пиксели. может ли он использоваться точно так же, как и андроид? и лучше ли передавать изображение в виде массива? спасибо btw :) – user5956131

+0

** 1. ** Доступ к «плоскому» 3D-массиву намного эффективнее массива массивов массивов на любом языке. C имеет обманчивую функцию, которую вы используете в своем коде: вы можете выделить 'double a [w] [h] [3]' в стеке как эффективный непрерывный массив или использовать 'double *** b' и выделить 3 -мерной несмежной структуры в куче. Доступ к ** a [x] [y] [c] ** намного эффективнее, чем ** b [x] [y] [c] **, но стек - очень ограниченный ресурс. Скорее всего, ваш сбой происходит потому, что для большого растрового изображения это распределение не выполняется. –

Смежные вопросы