Question

I have been struggling with sending back a CV:Mat in JNI as a Java byte[] so that that it can be decoded successfully with BitmapFactory.decode(). When I first bring in my byte[] array(constructed using data from an Android Bitmap) from the Java side, I am able to successfully use it in the C++ OpenCV functions. I do this by building a Mat from the byte[] coming in and calling cv::imdecode on the Mat.

The problem comes when I return back to Android and attempt to use BitmapFactory to decode the byte array into an Android Bitmap. It returns null which indicates that there was a problem in the decoding. Am I incorrectly performing the operations before I return from JNI? Do I need to use cv::imencode since I had to use cv::imdecode on the entering byte[]?

Any and all help appreciated! Code sample is below where I convert the data I need from the Mat in JNI.

NOTE I am aware of using Apache Android_Bitmap functions, but using a byte array is a requirement I am currently working on.

    //inData is a char* pointer that is set to a char* cast of the jbyte* pointer for the   
   // incoming Array.

    cv::Mat inMat = cv::Mat(rows, columns, CV_8UC4, inData);
    cv::Mat decodedMat = cv::imdecode(inMat, 1);

    //convertImage is a function that changes the color space from BGR to Gray and then Gray to  
    //RGB. 

    convertImage(decodedMat, decodedMat);

    cv::cvtColor(decodedMat, decodedMat, CV_RGB2RGBA);
    jbyteArray jDataArray = env->NewByteArray(pixelDataLength);
    env->SetByteArrayRegion(jDataArray,0,pixelDataLength,(jbyte*)decodedMat.data);
    env->SetObjectField(in,dataArray,jDataArray);
    env->ReleaseByteArrayElements(pixelData, bytePointerForIn, 0);
Was it helpful?

Solution 2

Solved! It was combination of my original version of sending in the bytes by using Bitmap.compress() and then on the returned pixels using copyPixelsFromBuffer. Thanks to Buddy for pointing me in the right direction.

Android: 

//input was the original bitmap that was used to construct the byte[] array. I then used input.compress() in JPEG format to a Byte. Very important for it to be compressed in a format that will be recognized in cv::imdecode.

ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
                input.compress(CompressFormat.JPEG, 100, bos); 
                data1.pixelData = bos.toByteArray();
...

    //Reconstruction after JNI call
    ByteBuffer buffer2 = ByteBuffer.wrap(data1.pixelData);
    Bitmap returnFromConvert = Bitmap.createBitmap(input.getWidth(),     
    input.getHeight(),Bitmap.Config.ARGB_8888);
    returnFromConvert.copyPixelsFromBuffer(buffer2);

OTHER TIPS

BitmapFactory expects the data provided to it to be in a known file format, but you are passing it raw pixels. You could make it work by calling cv::imencode, but perhaps a more natural solution for loading images from raw pixel data would be to create the original Java Bitmap object as mutable, and then calling the copyPixelsToBuffer and copyPixelsFromBuffer methods to get and set the pixel data in that object.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top