在Android jni cpp文件中将Mat转换为Bitmap

6
我正在进行Android的本地开发。我无法在Java中使用OpenCV。我会将Bitmap作为输入传递给JNI。我找到了一种方法将Bitmap->Mat进行转换。然后我可以处理()Mat图像类型。现在我需要重新将处理过的Mat->Bitmap并将其发送到Java文件。
我无法找到任何有关如何在JNI C ++中执行Mat->Bitmap转换的帖子。
如果您能提供任何建议,那将是非常有帮助的。
1个回答

9
我曾遇到过同样的问题,这段代码是解决方案:
jobject mat_to_bitmap(JNIEnv * env, Mat & src, bool needPremultiplyAlpha, jobject bitmap_config){

    jclass java_bitmap_class = (jclass)env->FindClass("android/graphics/Bitmap");
    jmethodID mid = env->GetStaticMethodID(java_bitmap_class,
                                       "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");

    jobject bitmap = env->CallStaticObjectMethod(java_bitmap_class,
                                             mid, src.size().width, src.size().height, bitmap_config);
    AndroidBitmapInfo  info;
    void* pixels = 0;

    try {
        //validate
        CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
        CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4);
        CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
        CV_Assert(pixels);

        //type mat
        if(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888){
            Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if(src.type() == CV_8UC1){
                cvtColor(src, tmp, CV_GRAY2RGBA);
            } else if(src.type() == CV_8UC3){
                cvtColor(src, tmp, CV_RGB2RGBA);
            } else if(src.type() == CV_8UC4){
                if(needPremultiplyAlpha){
                    cvtColor(src, tmp, COLOR_RGBA2mRGBA);
                }else{
                    src.copyTo(tmp);
                }
            }

        } else{
            Mat tmp(info.height, info.width, CV_8UC2, pixels);
            if(src.type() == CV_8UC1){
                cvtColor(src, tmp, CV_GRAY2BGR565);
            } else if(src.type() == CV_8UC3){
                cvtColor(src, tmp, CV_RGB2BGR565);
            } else if(src.type() == CV_8UC4){
                cvtColor(src, tmp, CV_RGBA2BGR565);
            }
        }
        AndroidBitmap_unlockPixels(env, bitmap);
        return bitmap;
    } catch(cv::Exception e){
        AndroidBitmap_unlockPixels(env, bitmap);
        jclass je = env->FindClass("org/opencv/core/CvException");
        if(!je) je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return bitmap;
    } catch (...){
        AndroidBitmap_unlockPixels(env, bitmap);
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
        return bitmap;
    }
}

你可以这样调用:

JNIEXPORT jobject JNICALL Java_com_duongtd_project_MyNDK_myfunction
    (JNIEnv *env, jclass ob, jobject bitmap){

    Mat src = 
    ....


    //get source bitmap's config
    jclass java_bitmap_class = (jclass)env->FindClass("android/graphics/Bitmap");
    jmethodID mid = env->GetMethodID(java_bitmap_class, "getConfig", "()Landroid/graphics/Bitmap$Config;");
    jobject bitmap_config = env->CallObjectMethod(bitmap, mid);
    jobject _bitmap = mat_to_bitmap(env, src, false, bitmap_config);

    AndroidBitmap_unlockPixels(env, bitmap);

    //and finally you can get bitmap for android
    return _bitmap;
}

不要忘记声明:

#include <android/bitmap.h>

我知道你有一种将Android位图转换为C++ Mat的解决方案,但我在这里发布是因为以上代码可能存在问题:

JNIEXPORT jobject JNICALL Java_com_duongtd_project_MyNDK_myfunction
    (JNIEnv *env, jclass ob, jobject bitmap){
    int ret;
    AndroidBitmapInfo info;
    void* pixels = 0;

    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME,"AndroidBitmap_getInfo() failed ! error=%d", ret);
        return NULL;
    }

    if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888 ) {
        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME,"Bitmap format is not RGBA_8888!");
        return NULL;
    }

    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
        __android_log_print(ANDROID_LOG_VERBOSE, APPNAME,"AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

    // init our output image
    Mat mbgra(info.height, info.width, CV_8UC4, pixels);

    ...
}

代码将CV_8UC1 / CV_8UC3 / CV_8UC4转换。有没有想法如何将CV_32FC3 / CV_32FC4 Mat转换为Android位图。 - Akash Goyal
为什么在Java_com_duongtd_project_MyNDK_myfunction中传递一个位图对象,而你只是获取它的Config呢?为什么不直接传递Config? - Ian Butler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接