JNI layer Bitmap to OpenCV Mat
Most of the image types provided by Java are Bitmap types (ARGB? 8888 or RGB? 565)
If you need to use OpenCV for processing, you need to convert Bitmap to cv::Mat.
Suppose the input picture is: Job object obj? Bitmap
The output picture is: Job object obj ﹣ bitmapout
#include <android/bitmap.h> #include <opencv/cv.hpp> #include <opencv2/opencv.hpp> #include <opencv2/core.hpp> #define ASSERT(status, ret) if (!(status)) { return ret; } #define ASSERT_FALSE(status) ASSERT(status, false) bool BitmapToMatrix(JNIEnv * env, jobject obj_bitmap, cv::Mat & matrix) { void * bitmapPixels; // Save picture pixel data AndroidBitmapInfo bitmapInfo; // Save picture parameters ASSERT_FALSE( AndroidBitmap_getInfo(env, obj_bitmap, &bitmapInfo) >= 0); // Get picture parameters ASSERT_FALSE( bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888 || bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565 ); // Only ARGB? 8888 and RGB? 565 are supported ASSERT_FALSE( AndroidBitmap_lockPixels(env, obj_bitmap, &bitmapPixels) >= 0 ); // Get picture pixels (lock memory block) ASSERT_FALSE( bitmapPixels ); if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) { cv::Mat tmp(bitmapInfo.height, bitmapInfo.width, CV_8UC4, bitmapPixels); // Establish temporary mat tmp.copyTo(matrix); // Copy to target matrix } else { cv::Mat tmp(bitmapInfo.height, bitmapInfo.width, CV_8UC2, bitmapPixels); cv::cvtColor(tmp, matrix, cv::COLOR_BGR5652RGB); } AndroidBitmap_unlockPixels(env, obj_bitmap); // Unlock return true; } bool MatrixToBitmap(JNIEnv * env, cv::Mat & matrix, jobject obj_bitmap) { void * bitmapPixels; // Save picture pixel data AndroidBitmapInfo bitmapInfo; // Save picture parameters ASSERT_FALSE( AndroidBitmap_getInfo(env, obj_bitmap, &bitmapInfo) >= 0); // Get picture parameters ASSERT_FALSE( bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888 || bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGB_565 ); // Only ARGB? 8888 and RGB? 565 are supported ASSERT_FALSE( matrix.dims == 2 && bitmapInfo.height == (uint32_t)matrix.rows && bitmapInfo.width == (uint32_t)matrix.cols ); // It must be a 2-dimensional matrix with the same length and width ASSERT_FALSE( matrix.type() == CV_8UC1 || matrix.type() == CV_8UC3 || matrix.type() == CV_8UC4 ); ASSERT_FALSE( AndroidBitmap_lockPixels(env, obj_bitmap, &bitmapPixels) >= 0 ); // Get picture pixels (lock memory block) ASSERT_FALSE( bitmapPixels ); if (bitmapInfo.format == ANDROID_BITMAP_FORMAT_RGBA_8888) { cv::Mat tmp(bitmapInfo.height, bitmapInfo.width, CV_8UC4, bitmapPixels); switch (matrix.type()) { case CV_8UC1: cv::cvtColor(matrix, tmp, cv::COLOR_GRAY2RGBA); break; case CV_8UC3: cv::cvtColor(matrix, tmp, cv::COLOR_RGB2RGBA); break; case CV_8UC4: matrix.copyTo(tmp); break; default: AndroidBitmap_unlockPixels(env, obj_bitmap); return false; } } else { cv::Mat tmp(bitmapInfo.height, bitmapInfo.width, CV_8UC2, bitmapPixels); switch (matrix.type()) { case CV_8UC1: cv::cvtColor(matrix, tmp, cv::COLOR_GRAY2BGR565); break; case CV_8UC3: cv::cvtColor(matrix, tmp, cv::COLOR_RGB2BGR565); break; case CV_8UC4: cv::cvtColor(matrix, tmp, cv::COLOR_RGBA2BGR565); break; default: AndroidBitmap_unlockPixels(env, obj_bitmap); return false; } } AndroidBitmap_unlockPixels(env, obj_bitmap); // Unlock return true; } JNIEXPORT void JNICALL Java_com_example_MainActivity_JniBitmapExec(JNIEnv * env, jobject /* this */, jobject obj_bitmap, jobject obj_bitmapOut) { cv::Mat matBitmap; bool ret = BitmapToMatrix(env, obj_bitmap, matBitmap); // Bitmap to cv::Mat if (ret == false) { return; } // opencv processing of mat ret = MatrixToBitmap(env, matBitmap, obj_bitmapOut); // Bitmap to cv::Mat if (ret == false) { return; } }
When creating a temporary cv::Mat, you can read it through the passed address and access address, or overwrite the access address.
In this way, cv::Mat can be established or saved to bitmap.
Just pay attention to the format conversion under different pictures.