What to pass to Android’s NDK so an image can be loaded with OpenCV?

Issue

info

I have an Android NDK / OpenCV project (running native c++ code).

I’m trying to load an image to the NDK, so I’m loading an image as a bitmap, so I can get it’s path.

Instead of passing the whole image to the NDK (like this answer, this answer or others), I want to just pass a string (e.g. the image path) or a pointer or something like this to the NDK, and read the image from the NDK with OpenCV.

I tried to use OpenCV’s Face Detection example as reference, but it doesn’t really do what I’m trying to do.

To get the path string in Java I tried this:

Uri uri  data.getData();
String imagePath  uri.getEncodedPath();

Or this:

Cursor imageCursor;
int imageNameIndex, imageSizeIndex;
Uri uri  data.getData();
imageCursor  getContentResolver().query(uri, null, null, null, null);
imageNameIndex  imageCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
String imagePath  imageCursor.getString(nameIndex);

Or that:

String imageFullPath  Environment.getExternalStorageDirectory() + "/Pictures/" + imagePath;

Or that:

String imageFullPath  Environment.DIRECTORY_PICTURES + "/" + imagePath;

which got me strings like /storage/emulated/0/Pictures/my-image.jpg, Pictures/my-image.jpg, my-image.jpg or /document/image%3A167.

Then I’m passing the string to the NDK (convert it to char *) and try to load an image on C++ with OpenCV’s imread:

Mat image  imread(image_path, IMREAD_COLOR);

All of the above trials result in an empty Mat object (all int values equal 0 and pointers are NULL).

I also tried similar approach with pointers.

question

Is this an OpenCV issue? Should I initialize the Mat in a certain way?

If not, what string / pointer should I pass to the NDK so it can load the image?

Solution

Pass pointer

Java side:

Activity.java:

// create a mat object with CvType.CV_8UC4, for Android's RGBA_8888
Mat passToNativeMat  new Mat(height, width, CvType.CV_8UC4);

// convert (for example) a bitmap image to Mat object
Utils.bitmapToMat(bitmap, passToNativeMat);

// get the native address of the Mat object created
long passToNativeMatAddress  passToNativeMat.getNativeObjAddr();

// call the Native function
String imageToJNIResult  imageToJNI(passToNativeMatAddress);

// native declarations
public native String imageToJNI(long imagePointer);

Native side:

native-lib.cpp:

extern "C"
JNIEXPORT jstring JNICALL
Java_package_activity_imageToJNI(
        JNIEnv* env,
        jobject thiz,
        jlong imagePointer) {

    Mat& image_in_native  *(Mat*) imagePointer;

    // do something with image Mat object

    string return_string  "Return string";

    return env->NewStringUTF(return_string.c_str());

}

Pass byte array

Java side:

public native String byteToJNI(byte[] myArray);

Native side:

extern "C" JNIEXPORT jstring JNICALL
Java_package_activity_byteToJNI(
        JNIEnv* env,
        jobject thiz,
        jbyteArray array) {

    Mat * mat  ByteToMat(array);

    string return_string  "Return string";

    return env->NewStringUTF(return_string.c_str());

}

Answered By – orangesomethingorange

Leave a Comment