如何在Android模拟器上显示Mat图像?使用NDK

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Android模拟器上显示Mat图像?使用NDK相关的知识,希望对你有一定的参考价值。

我想在android模拟器上显示Mat图像。我将一个assetManager从java传递给c++并将图像作为资产加载。然后我执行AAsset_read,并将图像数据保存到char *缓冲区,并使用cv::imdecode转换为Mat。从这里开始,如何将Mat图像添加到模拟器?

在默认的stringFromJNI方法中,它们似乎使用return->envNewStringUTF(hello.c_str());来显示文本:

Java_com_example_user_project_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */) {

std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());

那么我如何用Mat图像来做这个呢?

编辑:这是我的c ++代码:

JNIEXPORT jintArray JNICALL     Java_com_example_user_activity_MainActivity_generateAssets(JNIEnv* env,jobject thiz,jobject assetManager) {

AAsset* img;

AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
    AAsset *asset = AAssetManager_open(mgr, filename, AASSET_MODE_UNKNOWN);

    if(strcmp(filename, "hi.jpg")==0 ) {
        img = asset;
    }
}
long sizeOfImg = AAsset_getLength(img);
char* buffer = (char*) malloc (sizeof(char)*sizeOfImg);
AAsset_read(img, buffer, sizeOfImg);


std::vector<char> data(buffer, buffer + sizeOfImg);

cv::Mat h = cv::imdecode(data, IMREAD_UNCHANGED);

jintArray resultImage = env->NewIntArray(h.total());
jint *_data = new jint[h.total()];
for (int i = 0; i < h.total(); i++) {
    char b = h.data[4 * i];
    char g = h.data[4 * i + 1];
    char r = h.data[4 * i + 2];
    char a = 255;
    _data[i] = (((jint) a << 24) & 0xFF000000) + (((jint) r << 16) & 0x00FF0000) +
               (((jint) g << 8) & 0x0000FF00) + ((jint) b & 0x000000FF);
}
env->SetIntArrayRegion(resultImage, 0, h.total(), _data);
delete[]_data;
return resultImage;

}

和java代码:

    assetManager = getAssets();
    resultImage = generateAssets(assetManager);

    Bitmap imageinjava = Bitmap.createBitmap(resultImage, 100,100, Bitmap.Config.ARGB_8888);

    ImageView tv1;
    tv1= (ImageView) findViewById(R.id.image);
    tv1.setImageBitmap(imageinjava);
答案

为了转换您的原生Mat图像,您可以这样做:

JNIEXPORT jintArray JNICALL  Java_com_example_user_activity_MainActivity_generateAssets(JNIEnv* env, jobject thiz, jobject assetManager) {
AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
AAsset *img = AAssetManager_open(mgr, "hi.jpg", AASSET_MODE_UNKNOWN);

long sizeOfImg = AAsset_getLength(img);
char* buffer = (char*)AAsset_getBuffer(img);

std::vector<char> data(buffer, buffer + sizeOfImg);

cv::Mat h = cv::imdecode(data, IMREAD_UNCHANGED);

jintArray resultImage = env->NewIntArray(h.total());
jint *_data = new jint[h.total()];
for (int i = 0; i < h.total(); i++) {
    char b = h.data[h.channels() * i];
    char g = h.data[h.channels() * i + 1];
    char r = h.data[h.channels() * i + 2];
    char a = 255;
    _data[i] = (((jint) a << 24) & 0xFF000000) + (((jint) r << 16) & 0x00FF0000) +
               (((jint) g << 8) & 0x0000FF00) + ((jint) b & 0x000000FF);
}
env->SetIntArrayRegion(resultImage, 0, h.total(), _data);
delete[]_data;
return resultImage;

}

在你的java代码中就像这样

    int[] result = generateAssets(getAssets());
    Bitmap bitmap = Bitmap.createBitmap(result, yourimagewidth, yourimageheight, Bitmap.Config.ARGB_8888);

如果要在c ++和java之间传递本机Mat对象 - 返回指向Mat的指针并稍后将其传递给本机函数;

Mat *mat = new Mat(100, 100);
return (jlong) mat;

以上是关于如何在Android模拟器上显示Mat图像?使用NDK的主要内容,如果未能解决你的问题,请参考以下文章

无法同时显示五个 Mat 图像(C++、OpenCV)

如何在android手机中接收opencv图像

React-native:图像未显示在 android 设备中;但在模拟器中完美显示

如何将多个(超过 4 个)`CV::Mat` 图像`Size(M, N), CV_8UC1` 加入到一个 RGBA 图像中?

如何在 Opencv 中显示一个 Mat

BlackBerry:要在模拟器中显示的应用程序上显示的图像