jni-Android Bitmap与OpenCV cv::Mat互转

这篇具有很好参考价值的文章主要介绍了jni-Android Bitmap与OpenCV cv::Mat互转。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

在封装so库的时候,底层c++代码的实现使用了OpenCV对图片进行操作,而Android中从摄像头中获取到的图片数据类型是Bitmap数据类型的,所以这里就避免不了做数据类型的转换。转换的方案主要有两种,

  • 一种是封装的JNI接口方法直接接收cv::Mat数据类型的参数,

  • 第二种是JNI方法的接口接收Bitmap数据类型的参数,在JNI中实现Bitmap到cv::Mat的转换。

– 资料

JNI将Android Bitmap转为OpenCV的Mat_jni bitmap 转为mat_修炼之路的博客-CSDN博客

使用OpenCV的SDK实现数据类型的转换

第一种方法,如果想在Android中使用cv::Mat的数据类型,我们可以直接通过导入OpenCV的SDK,然后通过opencv的Utils实现bitmap到cv::Mat的转换。

缺点在于需要添加opencv的库文件,会导致最终的apk文件变大。

Android studio中添加OpenCV SDK参考:Android 使用OpenCV SDK 开源库—傻瓜式教程_opencvsdk用法_sunbofiy23的博客-CSDN博客

方式一:

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 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
Mat mat = new Mat(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, mat);

其中,CvType.CV_8UC4 表示位图的数据类型为 8 位无符号整数,该类型表示每个像素使用 4 个通道(RGBA)。

方式三:

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
Mat mat = new Mat();
mat.create(bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC4);
Utils.bitmapToMat(bitmap, mat);

其中,mat.create 方法用于创建一个空的 cv::Mat 对象,并指定其行数、列数和数据类型。

需要注意的是,Utils.bitmapToMat 是 OpenCV 中的辅助方法,用于将 Android 的 Bitmap 转换为 cv::Mat,需要在使用前确保已经导入 OpenCV 库。

JNI实现Bitmap到Mat的转换

– 代码1–CSDN找的

JNI将Android Bitmap转为OpenCV的Mat_jni bitmap 转为mat_修炼之路的博客-CSDN博客

#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
        )

– 代码2 – chatGpt中写的代码

#include <jni.h>
#include <opencv2/opencv.hpp>

using namespace cv;

extern "C"
JNIEXPORT void JNICALL
Java_com_example_android_MainActivity_nativeBitmapToMat(JNIEnv *env, jobject thiz,
                                                        jobject bitmap) {
    AndroidBitmapInfo info;
    void* pixels;
    Mat img;

    // 获取 Bitmap 的信息与像素数据
    if (AndroidBitmap_getInfo(env, bitmap, &info) != ANDROID_BITMAP_RESULT_SUCCESS ||
        AndroidBitmap_lockPixels(env, bitmap, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
        return;
    }

    // 创建 Mat 对象并拷贝像素数据
    img.create(info.height, info.width, CV_8UC4);
    memcpy(img.data, pixels, info.stride * info.height);

    // 解锁像素数据,释放资源
    AndroidBitmap_unlockPixels(env, bitmap);
}

– 代码3 – paddle fastdeploy中 实现

https://github.com/PaddlePaddle/FastDeploy/blob/develop/java/android/fastdeploy/src/main/cpp/fastdeploy_jni/bitmap_jni.cc文章来源地址https://www.toymoban.com/news/detail-790095.html

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

cv::Mat CreateZeroCopyRGBAFromBitmap(JNIEnv *env, jobject j_argb8888_bitmap) {
  cv::Mat c_rgba;
  AndroidBitmapInfo j_bitmap_info;
  if (AndroidBitmap_getInfo(env, j_argb8888_bitmap, &j_bitmap_info) < 0) {
    LOGE("Invoke AndroidBitmap_getInfo() failed!");
    return c_rgba;
  }
  if (j_bitmap_info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
    LOGE("Only Bitmap.Config.ARGB8888 color format is supported!");
    return c_rgba;
  }
  void *j_bitmap_pixels;
  if (AndroidBitmap_lockPixels(env, j_argb8888_bitmap, &j_bitmap_pixels) < 0) {
    LOGE("Invoke AndroidBitmap_lockPixels() failed!");
    return c_rgba;
  }
  cv::Mat j_bitmap_im(static_cast<int>(j_bitmap_info.height),
                      static_cast<int>(j_bitmap_info.width), CV_8UC4,
                      j_bitmap_pixels); // no copied.
  c_rgba = j_bitmap_im; // ref only.
  if (AndroidBitmap_unlockPixels(env, j_argb8888_bitmap) < 0) {
    LOGE("Invoke AndroidBitmap_unlockPixels() failed!");
    return c_rgba;
  }
  return c_rgba;
}

jboolean ARGB888Bitmap2RGBA(JNIEnv *env, jobject j_argb8888_bitmap,
                            cv::Mat *c_rgba) {
  // Convert the android bitmap(ARGB8888) to the OpenCV RGBA image. Actually,
  // the data layout of ARGB8888 is R, G, B, A, it's the same as CV RGBA image,
  // so it is unnecessary to do the conversion of color format, check
  // https://developer.android.com/reference/android/graphics/Bitmap.Config#ARGB_8888
  // to get the more details about Bitmap.Config.ARGB8888
  *c_rgba = CreateZeroCopyRGBAFromBitmap(env, j_argb8888_bitmap);
  if (c_rgba->empty()) {
    return JNI_FALSE;
  }
  return JNI_TRUE;
}

jboolean ARGB888Bitmap2BGR(JNIEnv *env, jobject j_argb8888_bitmap,
                           cv::Mat *c_bgr) {
  cv::Mat c_rgba;
  if (!ARGB888Bitmap2RGBA(env, j_argb8888_bitmap, &c_rgba)) {
    return JNI_FALSE;
  }
  // TODO: Use the neon instruction to optimize this conversion.
  // COLOR_RGBA2BGR will allocate memories for new mat.
  cv::cvtColor(c_rgba, *(c_bgr), cv::COLOR_RGBA2BGR);
  return JNI_TRUE;
}

jboolean RGBA2ARGB888Bitmap(JNIEnv *env, jobject j_argb8888_bitmap,
                            const cv::Mat &c_rgba) {
  AndroidBitmapInfo j_bitmap_info;
  if (AndroidBitmap_getInfo(env, j_argb8888_bitmap, &j_bitmap_info) < 0) {
    LOGE("Invoke AndroidBitmap_getInfo() failed!");
    return JNI_FALSE;
  }
  void *j_bitmap_pixels;
  if (AndroidBitmap_lockPixels(env, j_argb8888_bitmap, &j_bitmap_pixels) < 0) {
    LOGE("Invoke AndroidBitmap_lockPixels() failed!");
    return JNI_FALSE;
  }
  // no copied, but point to bitmap data.
  cv::Mat j_bitmap_im(static_cast<int>(j_bitmap_info.height),
                      static_cast<int>(j_bitmap_info.width), CV_8UC4,
                      j_bitmap_pixels);
  // TODO: Use zero copy operation or neon to boost performance.
  c_rgba.copyTo(j_bitmap_im);
  if (AndroidBitmap_unlockPixels(env, j_argb8888_bitmap) < 0) {
    LOGE("Invoke AndroidBitmap_unlockPixels() failed!");
    return JNI_FALSE;
  }
  return JNI_TRUE;
}

jboolean BGR2ARGB888Bitmap(JNIEnv *env, jobject j_argb8888_bitmap,
                           const cv::Mat &c_bgr) {
  if (c_bgr.empty()) {
    return JNI_FALSE;
  }
  cv::Mat c_rgba;
  cv::cvtColor(c_bgr, c_rgba, cv::COLOR_BGR2RGBA);
  return RGBA2ARGB888Bitmap(env, j_argb8888_bitmap, c_rgba);
}

– 测试代码

//
// Created by admin on 2023/4/14.
//
#include <jni.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <android/bitmap.h>
#include <android/log.h>

extern "C" {

    // bitmap --> cv::Mat
    bool BitmapToMatrix(JNIEnv * env, jobject obj_bitmap, cv::Mat & matrix) {
        void * bitmapPixels;                                            // Save picture pixel data
        AndroidBitmapInfo bitmapInfo;                                   // Save picture parameters

        AndroidBitmap_getInfo(env, obj_bitmap, &bitmapInfo);        // Get picture parameters

        //Only ARGB_8888 and RGB_565 are supported
        if (bitmapInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888
            && bitmapInfo.format != ANDROID_BITMAP_FORMAT_RGB_565)
        {
            __android_log_print(ANDROID_LOG_INFO, "ncnn", "BitmapToMatrix err--1");
            return false;
        }

        AndroidBitmap_lockPixels(env, obj_bitmap, &bitmapPixels); // Get picture pixels (lock memory block)
        if (not bitmapPixels)
        {
            __android_log_print(ANDROID_LOG_INFO, "ncnn", "BitmapToMatrix err--2");
            return false;
        }

        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;
    }

    //bitmap --> cv::Mat
    bool nativeBitmapToMat(JNIEnv *env, jobject bitmap, cv::Mat& img) {
        AndroidBitmapInfo info;
        void* pixels;

        // 获取 Bitmap 的信息与像素数据
        if (AndroidBitmap_getInfo(env, bitmap, &info) != ANDROID_BITMAP_RESULT_SUCCESS ||
            AndroidBitmap_lockPixels(env, bitmap, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {

            __android_log_print(ANDROID_LOG_INFO, "ncnn", "nativeBitmapToMat err");
            return false;
        }

        // 创建 Mat 对象并拷贝像素数据
        img.create(info.height, info.width, CV_8UC4);
        memcpy(img.data, pixels, info.stride * info.height);

//        cv::imwrite("bitmap2mat_2.jpg", img);

        // 解锁像素数据,释放资源
        AndroidBitmap_unlockPixels(env, bitmap);

        return true;
    }



    JNIEXPORT jstring JNICALL Java_com_example_ad_1test_MainActivity_detectOneImage(JNIEnv* env, jobject thiz, jlong ptr, jobject bitmap) {

        cv::Mat img_tt;
        BitmapToMatrix(env, bitmap, img_tt);
        __android_log_print(ANDROID_LOG_INFO, "ncnn", "BitmapToMatrix 转换完成");

        cv::Mat img_tt2;
        nativeBitmapToMat(env, bitmap, img_tt2);
        __android_log_print(ANDROID_LOG_INFO, "ncnn", "nativeBitmapToMat 转换完成");

        std::string result = "reinterpret_cast<NcnnYolov5lite*>(ptr)->detectOneImage(img_tt)转换完成";

        return env->NewStringUTF(result.c_str());
    };

}

到了这里,关于jni-Android Bitmap与OpenCV cv::Mat互转的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • opencv学习(9):cv::Scalar、cv::Mat::zeros

            cv::Scalar是opencv的一个结构体,其定义如下:(c++中的结构体如下,可以存放1~4个数值。)         表示图像颜色时,单通道图像用下标[0]即可,三通道图像用下标[0]、[1]、[2]分别表示B、G、R通道         其中:                 白色:rgb(255,255,255)  

    2024年02月08日
    浏览(51)
  • 【debug】OpenCV出现问题:undefined reference to ‘cv::Mat::Mat()‘

    参考:动手学ROS2 分析原因: undefined reference to \\\'cv::Mat::Mat()\\\' 原因在于g++找不到库文件,解决方法就是我们帮助它定位到库文件的位置,并通过-L参数指定库目录,-l(小写L)指定库的名字。 解决方法: 在执行命令时添加后缀参数

    2024年02月08日
    浏览(40)
  • OpenCV:矩阵表达式:代数和cv::Mat

    OpenCV是一个强大的计算机视觉库,它提供了丰富的功能和工具,用于处理图像数据。在OpenCV中,矩阵是一种核心数据结构,而矩阵表达式则是一种强大的工具,用于在图像处理和计算机视觉任务中对矩阵进行代数运算。本文将深入探讨OpenCV中的矩阵表达式,以及它们与cv::Ma

    2024年01月19日
    浏览(38)
  • OpenCV中cv::Mat矩阵的四种遍历

    at方法遍历 单通道 运行结果 at方法遍历 多通道 (下面这种方式,既能遍历,又能修改) 运行结果: 对比程序:(下面这种方式,只能遍历,不能修改) 运行结果 第一种写法 运行结果 更一般的写法:把里面的3改成矩阵的通道数 a.channels() ,如下: 运行结果 上面这种写法

    2024年02月13日
    浏览(47)
  • [OpenCV][C++编程] cv::mat的定义与赋值

    可以通过在/目录下直接搜索opencv,确定opencv所在的目录: lopencv_core 是opencv的核心, -lopencv_highgui包含读取图像和显示图像的函数 -lopencv_imgproc包含图像处理函数(非机器学习方法),例如线性滤波,边缘检测、膨胀腐蚀、检测直线、仿射变换等等。 -lopencv_ml包含机器学习算法

    2024年02月09日
    浏览(43)
  • OpenCV - cv::Mat与unsigned char*数组或者float*数组相互转换,cv::Mat与std::vector的相互转换

    通常情况下,在同一个opencv项目传递cv::Mat可直接通过const cv::Mat img这种方式传递,但是如果需要进行跨语言传递,比如C++传递到C#或者C#传递到C++,那么通常这种情况下需要将cv::Mat转换为内存指针比如unsigned char指针或者float指针进行传递。 1.1 cv::Mat转换为unsigned char 数组、un

    2024年02月13日
    浏览(54)
  • 【opencv之cv::Mat数据深拷贝和浅拷贝探讨】

    很多时候写程序除了一个强大的架构,细节也很重要,俗话说的话细节决定成败嘛,在使用cv::Mat做图片处理的时候发现,这个数据类型存在深拷贝和浅拷贝的情况,遂想一探究竟。 假设这里原图数据为matSrc : copy方法 结果 matA = matSrc 浅拷贝 matB(matSrc ) 浅拷贝 matC = matSrc .cl

    2024年02月13日
    浏览(35)
  • 在IOS上YUV NV21格式的CVPixelBufferRef转opencv的RGB格式cv::Mat的方法

    因为业务需要,要做这样一个转换。目前写了两种转换方法。 在iphonex真机上运行,一种方法需要24ms一帧,CPU占用率85%,另一种需要17ms一帧,CPU占用率140%。下面就来详细说说。 转换思路是CVPixelBufferRef-UIImage-cv::Mat的路线。 直接上方法: 先是CVPixelBufferRef-UIImage的方法 然后是

    2024年02月12日
    浏览(35)
  • OpenCV 中的错误信息 “Layout of the output array img is incompatible with cv::Mat (step...

    OpenCV 中的错误信息 “Layout of the output array img is incompatible with cv::Mat (step[ndims-1] !)” 表示输出数组 img 的布局与 cv::Mat 类型不兼容。这种错误通常是在使用 OpenCV 进行图像处理时出现的,可能是由于输入和输出 Mat 类的尺寸不匹配、步长不符合要求等原因导致的。 为了更好地理

    2024年02月16日
    浏览(47)
  • OpenCV(一):Android studio jni配置OpenCV(亲测有效,保姆级)

    目录 1.下载OpenCV的SDK 2.创建Android Native C++项目 3.Android项目中导入OpenCV工程 4.导入OpenCV的库文件 5.实现opencv高斯模糊图像处理的demo 要在Android Studio中配置使用OpenCV库的C++方法,需要完成以下步骤: 1.下载OpenCV的SDK 首先,您可以从OpenCV官方网站(Releases - OpenCV )下载适用于And

    2024年02月03日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包