android - 使用 JNI 在图像上实现水彩效果

标签 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 Activity 调用 native 函数的代码。

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,所以请帮助我。

更新

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 代码调用的。

最佳答案

您的 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 位图对象。参见 an other of my answers here了解详情。

关于android - 使用 JNI 在图像上实现水彩效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13538905/

相关文章:

android - IntentService 的蓝牙连接问题

android - 通过命令行截取的Android屏幕截图的图像格式

android - Firebase 在线到 Android 离线数据存储

java - 类似于java中的fork()函数

image-processing - OpenCV:立体声校正问题(使用书中的示例代码)

python - 使用 NumPy 对灰度图像进行直方图均衡化

java - 将数组从 JNI 传递到 Java

c++ - 加载共享库时出错 : jvm. dll

java - 什么是 native 指针和返回地址?

java - 您如何找到当前与当前 ParseUser 关联的 ParseRoles?