OpenCV on Android: practices and tips

Transfer MAT objects from Android to NDK

The main idea is to use the address of an MAT object in order to manipulate
the data.

Basically, we have a function playing as a bridge between Java APIs and NDK:

public native void function_name(long matAddress);

To call the function, we use Mat’s address by calling getNativeObjAddr().
All computations in NDK will affect the content of MAT in both Java and
NDK layers.

In the NDK code, to use cv::Mat object regarding java Mat, we can use
static_cast:

Mat& im = *(static_cast<Mat*>(addrImg));

Notes

There is a huge different in image channels between Java OpenCV and NDK OpenCV.
When we decode the path or file to a bitmap in Java, we have to convert
the bitmap to ARGB_8888 color channel, otherwise it does not work. Actually,
it also can work on RGB_565 but for some reasons I can not remember, I always
use ARGB_8888 in the project.

Bitmap bm32_image = bm.copy(Bitmap.Config.ARGB_8888, true);

To manipulate the image correctly in NDK, we should covert it to the normal
RGB channel, otherwise sometimes we get some bugs making us frustrating.

Noting that OpenCV’s Camera is not able to set the portrait mode. One workaround
is to turn the Activity to landscape by putting the following line inside tag Activity
in AndroidManifest.xml

android:screenOrientation="landscape"

Data Manipulation

unsigned char Mat

It is troublesome when we want to assign a value of 255 to an unsigned char Mat
because this language does not support unsigned char as a primitive type.
One workaround is to allocate a 16S Mat, manipulate on that matrix, and
finally convert to 8U.

Point2f and Point

To convert MatOfPoint to MatOfPoint2f, we use the constructor:

MatOfPoint matofpoint = new MatOfPoint(matofpoint2f.toArray());

Accessing the pixel values

In order to retrieve and assign pixel value, we use the getter/setter from Mat.