OpenCV OpenCL:在Android的JNI层中将Mat转换为位图

问题描述 投票:0回答:2

[有关使用Utils.matToBitmap()函数将Mat转换为Bitmap的几篇文章。但是我假设此函数只能在导入Utils类之后在Java层中调用。

我想将数据传输到uint32_t * bmpContent指向的内存地址;在下面的代码中。

JNIEXPORT void JNICALL Java_com_nod_nodcv_NodCVActivity_runfilter(
    JNIEnv *env, jclass clazz, jobject outBmp, jbyteArray inData,
    jint width, jint height, jint choice, jint filter)
{
    int outsz = width*height;
    int insz = outsz + outsz/2;
    AndroidBitmapInfo bmpInfo;

    if (AndroidBitmap_getInfo(env, outBmp, &bmpInfo) < 0) {
        throwJavaException(env,"gaussianBlur","Error retrieving bitmap meta data");
        return;
    }
    if (bmpInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        throwJavaException(env,"gaussianBlur","Expecting RGBA_8888 format");
        return;
    }
    uint32_t* bmpContent;
    if (AndroidBitmap_lockPixels(env, outBmp,(void**)&bmpContent) < 0) {
        throwJavaException(env,"gaussianBlur","Unable to lock bitmap pixels");
        return;
    }

    //This function runs the kernel on the inData and gives a matrix
    tester(env, clazz, bmpContent, outsz, inData, insz, width, height);

    AndroidBitmap_unlockPixels(env, outBmp);
}

这大致是测试器功能中发生的事情:

jbyte*  b_mat  = env->GetByteArrayElements(inData, 0);
cv::Mat mdata(h, w, CV_8UC4, (unsigned char *)b_mat); 
cv::Mat mat_src = imdecode(mdata,1); 

cv::UMat umat_src = mat_src.getUMat(cv::ACCESS_READ, cv::USAGE_ALLOCATE_DEVICE_MEMORY);
cv::UMat umat_dst (mat_src.size(), mat_src.type(), cv::ACCESS_WRITE, cv::USAGE_ALLOCATE_DEVICE_MEMORY);

kernel.args(cv::ocl::KernelArg::ReadOnlyNoSize(umat_src), cv::ocl::KernelArg::ReadWrite(umat_dst));

size_t globalThreads[3] = {static_cast<unsigned int>(mat_src.cols), static_cast<unsigned int>(mat_src.rows), 1 };

bool success = kernel.run(3, globalThreads, NULL, true);

cv::Mat mat_dst = umat_dst.getMat(cv::ACCESS_READ);

mat_dst保存我需要的结果,并且需要在手机上显示。我怎样才能做到这一点?

我假设我需要将数据从mat_dst复制到bmpContent位置,但是我不确定。

android opencv java-native-interface opencl
2个回答
0
投票

使用此将您的Mat转换为位图。

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,dst,false,bitmap_config);

AndroidBitmap_unlockPixels(env, bitmap);
return _bitmap;

0
投票

如果确实需要从JNI层调用此方法,则可以简单地使用OpenCV的原始C ++实现Here。示例代码如下:

#include <jni.h>
#include <string>
#include <android/bitmap.h>
#include "opencv2/opencv.hpp"

// using namespace cv;


void MatToBitmap2 (JNIEnv * env, cv::Mat src, jobject bitmap, bool needPremultiplyAlpha)
{
    AndroidBitmapInfo  info;
    void*              pixels = 0;
    try {
        // LOGD("nMatToBitmap");
        CV_Assert( AndroidBitmap_getInfo(env, bitmap, &info) >= 0 );
        CV_Assert( info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
                   info.format == ANDROID_BITMAP_FORMAT_RGB_565 );
        CV_Assert( src.dims == 2 && info.height == (uint32_t)src.rows && info.width == (uint32_t)src.cols );
        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 );
        if( info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 )
        {
            cv::Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if(src.type() == CV_8UC1)
            {
                cvtColor(src, tmp, cv::COLOR_GRAY2RGBA);
            } else if(src.type() == CV_8UC3){
                cvtColor(src, tmp, cv::COLOR_RGB2RGBA);
            } else if(src.type() == CV_8UC4){
                if(needPremultiplyAlpha) cvtColor(src, tmp, cv::COLOR_RGBA2mRGBA);
                else src.copyTo(tmp);
            }
        } else {
            // info.format == ANDROID_BITMAP_FORMAT_RGB_565
            cv::Mat tmp(info.height, info.width, CV_8UC2, pixels);
            if(src.type() == CV_8UC1)
            {
                cvtColor(src, tmp, cv::COLOR_GRAY2BGR565);
            } else if(src.type() == CV_8UC3){
                cvtColor(src, tmp, cv::COLOR_RGB2BGR565);
            } else if(src.type() == CV_8UC4){
                cvtColor(src, tmp, cv::COLOR_RGBA2BGR565);
            }
        }
        AndroidBitmap_unlockPixels(env, bitmap);
        return;
    } catch(const cv::Exception& e) {
        AndroidBitmap_unlockPixels(env, bitmap);
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return;
    } catch (...) {
        AndroidBitmap_unlockPixels(env, bitmap);
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
        return;
    }
}

该函数直接从OpenCV来源采用,并包含对不同格式的一些额外检查。如果您知道将要使用哪种矩阵格式,则可以剥离检查。

mat_dst保存我需要的结果,并且需要在手机上显示。我该怎么办?

您可以呼叫类似:

extern "C"
JNIEXPORT void JNICALL
Java_com_your_package_MainActivity_DoStuff(JNIEnv *env, jobject thiz,
                                                               jobject bitmap) {
// Do your stuff with mat_dst.

    try {
        MatToBitmap2(env, mat_dst, bitmap, false);
    }
    catch(const cv::Exception& e)
    {
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
    }
}

并在Java端定义它,如:

public native void DoStuff(Bitmap bitmap);

您不需要将任何东西返回到Java端,因为Bitmap类将是引用类型,而MatToBitmap2方法已经负责锁定和解锁像素缓冲区。

© www.soinside.com 2019 - 2024. All rights reserved.