JNI - 在本地处理缓慢 [英] jni - Slow processing in native
问题描述
切换到纯以获得更高的性能和处理速度,但不幸的是,我的应用程序太慢。此外,装载高分辨率的图像时,应用程序崩溃。
下面是我的全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屋!