在封装so库的时候,底层c++代码的实现使用了OpenCV对图片进行操作,而Android中从摄像头中获取到的图片数据类型是Bitmap数据类型的,所以这里就避免不了做数据类型的转换。转换的方案主要有两种,一种是封装的JNI接口方法直接接收cv::Mat数据类型的参数,第二种是JNI方法的接口接收Bitmap数据类型的参数,在JNI中实现Bitmap到cv::Mat的转换。
第一种方法,如果想在Android中使用cv::Mat的数据类型,我们可以直接通过导入OpenCV的SDK,然后通过opencv的Utils实现bitmap到cv::Mat的转换。缺点在于需要添加opencv的库文件,会导致最终的apk文件变大。
Android studio中添加OpenCV SDK参考:https://blog.csdn.net/qq_34123324/article/details/85330720
import org.opencv.android.Utils;
Mat mat = new Mat();
Bitmap bmp32 = bmp.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(bmp32, mat);
在JNI中接收Mat参数的时候,使用Jobject类型,然后再做个强制转换就行了
下面的方法实现了Bitmap到cv::Mat和cv::Mat到Bitmap的转换
#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);
}
//convert RGB to BGR
cv::cvtColor(matrix,matrix,cv::COLOR_RGB2BGR);
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;
}
}
注意在CMakelist文件中添加以下代码,不然编译的时候会报错
target_link_libraries( # Specifies the target library.
#在target_link_libraries中添加下面的依赖项
jnigraphics
)