I’m testing performance for manipulating Bitmap pixels on the JNI layer using OpenCv.
Two options:
1. Pass array of integers, manipulate the pixels and write pixels back to Bitmap. [41ms]
2. Pass the entire Bitmap. [35ms]
I noticed that it’s about 5ms faster to pass the Bitmap than passing the pixel array and assigning the array to a Bitmap.
The problem is that using option 2 I’m loosing the blue color and getting an orange color in place of the blue I’m expecting. The image is ARGB and it seems like its changed to RGBA? What could be the issue?
Method 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);
}
Method 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);
}
Solution 05/23:
The problem was that when using an array of integers and passing it to the JNI the byte order is changed from ARGB (java) to BGRA(native). This was fine for working with the pixels. However passing the actual Bitmap object when locking the pixels the byte order didn’t change so it required to change it after modifying the pixel data.
cvtColor(mbgra, mbgra, COLOR_BGR2RGBA, 4);
Opencv order is BGR not RGB. I’m gonna guess the A is in the right place (or you would be seeing translucent image), but blue and red would swap.