JNI Android Bitmap 和 cv::Mat 互相转换

4 篇文章 0 订阅

一、Android Bitmap 转 cv::Mat

要将Android Bitmap转换为cv::Mat格式,可以使用OpenCV库中的数据结构和函数。以下是一个高效简洁的方法来完成这一任务:

1. 安装OpenCV和Android NDK

确保你已经在Android项目中配置了OpenCV和Android NDK。你可以参考OpenCV的官方文档来配置你的Android项目。

2. 将Bitmap转换为cv::Mat

以下是Kotlin和C++代码的示例,演示如何将Bitmap对象转换为cv::Mat对象。

Kotlin代码
external fun convertBitmapToMat(bitmap: Bitmap): Long

fun main() {
    val bitmap: Bitmap = ... // 获取或生成Bitmap对象
    val matAddr = convertBitmapToMat(bitmap)
    if (matAddr != 0L) {
        val mat = Mat(matAddr) // 使用matAddr在Java/Kotlin中构建cv::Mat对象
        // 可以在这里使用mat进行进一步的处理
    }
}
C++代码

首先,确保在C++代码中包含OpenCV头文件和Android Bitmap处理头文件:

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

using namespace cv;

extern "C"
JNIEXPORT jlong JNICALL
Java_com_example_yourapp_MainActivity_convertBitmapToMat(JNIEnv *env, jobject obj, jobject bitmap) {
    AndroidBitmapInfo info;
    void* pixels = nullptr;
    cv::Mat mat;

    // 获取Bitmap信息
    if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
        return 0; // 返回0表示失败
    }

    // 锁定Bitmap以获取像素数据
    if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
        return 0; // 返回0表示失败
    }

    // 将Bitmap转换为cv::Mat
    if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
        mat = cv::Mat(info.height, info.width, CV_8UC4, pixels);
    } else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
        mat = cv::Mat(info.height, info.width, CV_8UC2, pixels);
        cv::cvtColor(mat, mat, cv::COLOR_BGR5652BGR);
    } else {
        // 解锁Bitmap
        AndroidBitmap_unlockPixels(env, bitmap);
        return 0; // 不支持的格式
    }

    // 复制数据以确保在Bitmap解锁后仍然可用
    mat = mat.clone();

    // 解锁Bitmap
    AndroidBitmap_unlockPixels(env, bitmap);

    // 返回cv::Mat对象的指针地址
    return reinterpret_cast<jlong>(new cv::Mat(mat));
}

解释

  1. 获取Bitmap信息
    使用AndroidBitmap_getInfo(env, bitmap, &info)获取Bitmap的宽度、高度和格式等信息。

  2. 锁定Bitmap以获取像素数据
    使用AndroidBitmap_lockPixels(env, bitmap, &pixels)锁定Bitmap并获取指向其像素数据的指针。

  3. 将Bitmap转换为cv::Mat
    根据Bitmap的格式创建对应的cv::Mat对象。对于RGBA_8888格式,直接创建CV_8UC4cv::Mat。对于RGB_565格式,创建CV_8UC2cv::Mat并使用cvtColor进行颜色转换。

  4. 复制数据
    使用clone()方法复制cv::Mat对象的数据,以确保在解锁Bitmap后数据仍然可用。

  5. 解锁Bitmap
    使用AndroidBitmap_unlockPixels(env, bitmap)解锁Bitmap对象。

  6. 返回cv::Mat对象的指针地址
    返回新创建的cv::Mat对象的指针地址。在Kotlin中,可以使用这个指针地址来创建cv::Mat对象进行进一步处理。

通过这种方式,你可以高效且简洁地将Bitmap对象转换为cv::Mat对象,并在C++代码中使用OpenCV进行进一步的图像处理。

二、 cv::Mat 转回 Android Bitmap

在 C++ 中,如果你使用了 OpenCV 将 Bitmap 转换为 cv::Mat 格式,可以通过以下步骤将 cv::Mat 转回 Bitmap

假设你已经有一个 cv::Mat 类型的图像 mat,你可以使用以下步骤将其转换回 Bitmap

  1. 获取 cv::Mat 的数据
    首先,你需要从 cv::Mat 中获取像素数据。注意,cv::Mat 的数据是连续的,可以直接使用指针操作。

  2. 创建 Bitmap 对象
    你需要使用与原始 Bitmap 相同的规格创建一个新的 Bitmap 对象,确保大小和格式与 cv::Mat 一致。

  3. cv::Mat 数据复制到 Bitmap
    你可以使用 Bitmap 提供的 copyPixelsFromBuffer 或者直接操作 Bitmap 的内存来复制数据。

以下是一个示例代码:

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

// 假设有一个 cv::Mat 类型的图像 mat 和 JNIEnv* env, jobject bitmap
void matToBitmap(JNIEnv* env, cv::Mat &mat, jobject bitmap) {
    void* bitmapPixels;
    AndroidBitmapInfo info;

    // 获取 Bitmap 信息
    AndroidBitmap_getInfo(env, bitmap, &info);

    // 锁定 Bitmap,以便将数据写入其中
    AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels);

    // 假设 mat 的类型与 bitmap 的格式匹配,例如都是 CV_8UC4 (ARGB_8888)
    // 如果类型不匹配,需要先转换 mat 的类型
    if (mat.type() == CV_8UC4) {
        memcpy(bitmapPixels, mat.data, mat.total() * mat.elemSize());
    } else {
        // 其他类型的转换可以使用 cv::cvtColor 来实现
        cv::Mat temp;
        cv::cvtColor(mat, temp, cv::COLOR_RGB2BGRA);
        memcpy(bitmapPixels, temp.data, temp.total() * temp.elemSize());
    }

    // 解锁 Bitmap
    AndroidBitmap_unlockPixels(env, bitmap);
}

这个示例代码假定 cv::MatBitmap 的格式是匹配的(例如都是 CV_8UC4 格式)。如果它们不匹配,你需要使用 cv::cvtColor 等 OpenCV 函数来进行格式转换。此外,请确保在调用 JNI 函数时处理可能的异常情况。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值