使用JNI实现水色对图像的影响

时间:2012-11-24 06:24:29

标签: android image-processing java-native-interface

我实现了一些代码用于Android中图像的水色效果,但它要慢一点(需要2分钟以上),现在我尝试在JNI中实现这个以获得更快的速度, 听到的是我的

的java代码

inPixels是Bitmap的像素。

 protected int[] filterPixels( int width, int height, int[] inPixels ) 
    {
        int levels = 256;
        int index = 0;

        int[] rHistogram = new int[levels];
        int[] gHistogram = new int[levels];
        int[] bHistogram = new int[levels];
        int[] rTotal = new int[levels];
        int[] gTotal = new int[levels];
        int[] bTotal = new int[levels];
        int[] outPixels = new int[width * height];

        for (int y = 0; y < height; y++) 
        {
            for (int x = 0; x < width; x++) 
            {
                for (int i = 0; i < levels; i++)
                    rHistogram[i] = gHistogram[i] = bHistogram[i] = rTotal[i] = gTotal[i] = bTotal[i] = 0;

                for (int row = -range; row <= range; row++) 
                {
                    int iy = y+row;
                    int ioffset;
                    if (0 <= iy && iy < height) 
                    {
                        ioffset = iy*width;
                        for (int col = -range; col <= range; col++) 
                        {
                            int ix = x+col;
                            if (0 <= ix && ix < width) {
                                int rgb = inPixels[ioffset+ix];
                                int r = (rgb >> 16) & 0xff;
                                int g = (rgb >> 8) & 0xff;
                                int b = rgb & 0xff;
                                int ri = r*levels/256;
                                int gi = g*levels/256;
                                int bi = b*levels/256;
                                rTotal[ri] += r;
                                gTotal[gi] += g;
                                bTotal[bi] += b;
                                rHistogram[ri]++;
                                gHistogram[gi]++;
                                bHistogram[bi]++;
                            }
                        }
                    }
                }

                int r = 0, g = 0, b = 0;
                for (int i = 1; i < levels; i++) 
                {
                    if (rHistogram[i] > rHistogram[r])
                        r = i;
                    if (gHistogram[i] > gHistogram[g])
                        g = i;
                    if (bHistogram[i] > bHistogram[b])
                        b = i;
                }
                r = rTotal[r] / rHistogram[r];
                g = gTotal[g] / gHistogram[g];
                b = bTotal[b] / bHistogram[b];
                outPixels[index] = (inPixels[index] & 0xff000000) | ( r << 16 ) | ( g << 8 ) | b;
                index++;
            }
        }

        return outPixels;
    }

**输出图片** enter image description here

我尝试将此java代码转换为c代码,但我没有错, 听取C

的代码
 void filterPixels( int width, int height, int inPixels[] )
    {



        int levels = 256;
        int index = 0;

        int rHistogram [levels];
        int gHistogram [levels];
        int bHistogram [levels];
        int rTotal   [levels];
        int gTotal [levels];
        int bTotal [levels];
        int outPixels [width * height];

        //Loop Variables
        int y ;
        int x ;
        int i ;
        int row ;
        int col ;
        int j ;

        int range = 5 ;

        for ( y = 0; y < height; y++)
        {
            for ( x = 0; x < width; x++)
            {
                for ( i = 0; i < levels; i++)
                    rHistogram[i] = gHistogram[i] = bHistogram[i] = rTotal[i] = gTotal[i] = bTotal[i] = 0;

                for ( row = -range; row <= range; row++)
                {
                    int iy = y+row;
                    int ioffset;
                    if (0 <= iy && iy < height)
                    {
                        ioffset = iy*width;
                        for ( col = -range; col <= range; col++)
                        {
                            int ix = x+col;
                            if (0 <= ix && ix < width) {
                                int rgb = inPixels[ioffset+ix];
                                int r = (rgb >> 16) & 0xff;
                                int g = (rgb >> 8) & 0xff;
                                int b = rgb & 0xff;
                                int ri = r*levels/256;
                                int gi = g*levels/256;
                                int bi = b*levels/256;
                                rTotal[ri] += r;
                                gTotal[gi] += g;
                                bTotal[bi] += b;
                                rHistogram[ri]++;
                                gHistogram[gi]++;
                                bHistogram[bi]++;
                            }
                        }
                    }
                }

                int r = 0, g = 0, b = 0;
                for ( j = 1; j < levels; j++)
                {
                    if (rHistogram[j] > rHistogram[r])
                        r = j;
                    if (gHistogram[j] > gHistogram[g])
                        g = j;
                    if (bHistogram[j] > bHistogram[b])
                        b = j;
                }
                r = rTotal[r] / rHistogram[r];
                g = gTotal[g] / gHistogram[g];
                b = bTotal[b] / bHistogram[b];
                outPixels[index] = (inPixels[index] & 0xff000000) | ( r << 16 ) | ( g << 8 ) | b;
                index++;
            }
        }
    }

我检查java代码和c代码的像素值是否相同(对于同一图像)

来自我的android活动的调用本机函数的代码。

int[] pix = new int[oraginal.getWidth() * oraginal.getHeight()];

                Bitmap bitmap = oraginal.copy(oraginal.getConfig(), true);
                bitmap.getPixels(pix, 0, bitmap.getWidth(), 0, 0,bitmap.getWidth(), bitmap.getHeight());
                filterPixelsJNI(bitmap.getWidth(), bitmap.getHeight(), pix);

                 bitmap.setPixels(pix, 0, bitmap.getWidth(), 0, 0,bitmap.getWidth(), bitmap.getHeight());
                 myView.setImageBitmap(bitmap);

这是我对JNI的第一次尝试,所以PLZ帮助我。

更新

public native void filterPixelsJNI( int width, int height, int inPixels[] );

JNI

 JNIEXPORT void JNICALL Java_com_testndk_HelloWorldActivity_filterPixelsJNI (JNIEnv * env, jobject obj , jint width,jint height,jint inPixels[]){

     filterPixels( width, height, inPixels);
 }

filterPixels方法是从c代码调用。

1 个答案:

答案 0 :(得分:2)

您的JNI代码存在一些问题。算法部分可能是正确的,但您没有正确处理Java数组到C数组的转换。

首先,Java_com_testndk_HelloWorldActivity_filterPixelsJNI的最后一个参数应该是jintArray类型,而不是jint []。这就是将Java数组传递给C代码的方法。

获得此数组后,您无法直接处理它,您必须将其转换为C数组:

JNIEXPORT void JNICALL Java_com_testndk_HelloWorldActivity_filterPixelsJNI (JNIEnv * env, jobject obj , jint width, jint height, jintArray inPixels) {

    int *c_inPixels = (*env)->GetIntArrayElements(env, inPixels, NULL);
    filterPixels( width, height, c_inPixels);
    // passing 0 as the last argument should copy native array to Java array
    (*env)->ReleaseIntArrayElements(env, inPixels, c_inPixels, 0);
}

我建议你看一下JNI文档,它解释了如何处理数组:http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html

请注意,现在使用android NDK处理Java Bitmap对象的方法更简单。有关详细信息,请参阅an other of my answers here