JNI将Android Bitmap转为OpenCV的Mat

导读

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

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

第一种方法,如果想在Android中使用cv::Mat的数据类型,我们可以直接通过导入OpenCV的SDK,然后通过opencv的Utils实现bitmap到cv::Mat的转换。缺点在于需要添加opencv的库文件会导致最终的apk文件变大

Android studio中添加OpenCV SDK参考:https://blog.csdn.net/qq_34123324/article/details/85330720

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类型,然后再做个强制转换就行了

JNI实现Bitmap到Mat的转换

下面的方法实现了Bitmap到cv::Mat和cv::Mat到Bitmap的转换

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

 

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Android中使用JNI调用OpenCV库来实现摄像头功能是可行的。以下是调用摄像头的简单步骤: 首先,你需要在Android项目中集成OpenCV库。可以通过将OpenCV库添加到Gradle依赖项或手动导入库文件来完成。 其次,创建一个JNI接口,将Java代码与C/C++代码进行绑定。JNI接口允许在Java和C/C++之间进行双向通信。 然后,在C/C++代码中编写与摄像头相关的功能。可以使用OpenCV提供的函数和类来处理视频流。例如,你可以使用VideoCapture类打开摄像头并获取图像帧。 接下来,在JNI接口中实现调用摄像头的功能。通过JNI接口,将Java代码的请求传递给C/C++函数来执行摄像头操作。你可以设置一个循环,不断从摄像头读取图像帧并进行处理。 最后,在Java代码中调用JNI接口中的方法来启动摄像头。可以使用SurfaceView来显示摄像头捕获的图像。你可以使用Camera类来控制摄像头的预览以及其他设置。 需要注意的是,在JNI和C/C++代码中处理摄像头操作时,要遵循正确的线程管理和图像处理技术,以确保流畅的手机摄像头应用程序。 总之,通过JNI调用OpenCV库,可以很方便地在Android上实现摄像头功能。项目中要同时涉及Java和C/C++代码,需要进行正确的接口绑定和线程管理。这样,你可以轻松地使用OpenCV函数和类来处理摄像头操作并实现自己的摄像头应用程序。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

修炼之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值