使用OpenCv进行NDK位图操作,蓝色变为橙色?

4
我正在使用OpenCv在JNI层测试操作Bitmap像素的性能。 两个选项:
1. 传递整数数组,操作像素并将像素写回Bitmap。[41ms]
2. 传递整个Bitmap。[35ms]
我注意到传递Bitmap比传递像素数组并将数组分配给Bitmap要快约5ms。
问题是使用选项2时,我丢失了蓝色并得到了一个橙色代替我期望的蓝色。图像是ARGB格式,似乎已更改为RGBA?可能出了什么问题? 方法1: Java
Bitmap out = Bitmap.createBitmap(width, height, Config.ARGB_8888);

int[] rgba = new int[width*height];

mSmasher.loadImage(imagePath, rgba, 0);

out.setPixels(rgba, 0, width, 0, 0, width, height);

JNI

JNIEXPORT void JNICALL Java_com_vblast_smasher_Smasher_loadImage
    (JNIEnv *pEnv, jobject obj, jstring jFilePath, jintArray jbgra, jint options)
{
    jint*  _bgra = pEnv->GetIntArrayElements(jbgra, 0);
    const char *filePath = pEnv->GetStringUTFChars(jFilePath, 0);

    if (NULL != filePath)
    {
        // init our output image
        Mat bgra(outputHeight, outputWidth, CV_8UC4, (unsigned char *)_bgra);

                // bgra image manipulations
    }

    pEnv->ReleaseIntArrayElements(jbgra, _bgra, 0);
    pEnv->ReleaseStringUTFChars(jFilePath, filePath);
}

方法2:

JNIEXPORT void JNICALL Java_com_vblast_smasher_Smasher_getLayersBitmap
    (JNIEnv *pEnv, jobject obj, jobject bitmap)
{
    int ret;
    AndroidBitmapInfo  info;
    void*              pixels = 0;

    if ((ret = AndroidBitmap_getInfo(pEnv, bitmap, &info)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888 )
    {
        LOGE("Bitmap format is not RGBA_8888!");
        return;
    }

    if ((ret = AndroidBitmap_lockPixels(pEnv, bitmap, &pixels)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    // init our output image
    Mat mbgra(info.height, info.width, CV_8UC4, pixels);

    mLayers[0].copyTo(mbgra);

    AndroidBitmap_unlockPixels(pEnv, bitmap);
}

解决方案 05/23:
问题在于当使用整数数组并将其传递到JNI时,字节顺序从ARGB(java)更改为BGRA(本机)。这对于处理像素来说是可以接受的。然而,在锁定像素时传递实际的Bitmap对象时,字节顺序不会更改,因此需要在修改像素数据后更改它。

cvtColor(mbgra, mbgra, COLOR_BGR2RGBA, 4); 

我对你的速度测试很感兴趣。你能总结一下这两种方法吗?我不明白第一种方法意味着什么。 - Bobbi Bennett
添加了更多细节...希望有意义 :) - Jona
2个回答

3

Opencv中的顺序是BGR而不是RGB。我猜字母A在正确的位置(否则您将看到半透明图像),但蓝色和红色会交换。


我有点记得在clrConvert(拼写可能不对)中有一个BGR2RGB。现在离我的opencv2refman.pdf很远,但也有mixchannels(同样的拼写问题)。 - Bobbi Bennett
1
啊!这就是解决方案。cvtColor(mbgra,mbgra,COLOR_BGR2RGBA,4); - Jona
1
由于您接近解决方案,我给您提供了答案。此外,这也让我知道了有参考手册这样的东西! :) - Jona
我怀疑你在执行这个操作时会浪费5毫秒时间。我无法想到避免交换的方法。 - Bobbi Bennett

1

在JNI中,颜色值以ARGB形式返回,而在JAVA中以RGBA形式返回。尝试一下:

alpha = (int) ((color & 0xFF000000) >> 24);
    blue = (int) ((color & 0xFF0000) >> 16);
    green = (int)((color & 0x00FF00) >> 8);
    red = (int) (color & 0x0000FF);
    blue = blue * alpha / 255;
    green = green * alpha / 255;
    red = red * alpha / 255;

    int tmp = 0;
    tmp = red;
    red = blue;
    blue = tmp;

    color =  ((alpha<< 24) & 0xFF000000) | ((blue<< 16) & 0xFF0000) |
                  ((green << 8) & 0x00FF00) |
                  (red & 0x0000FF);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接