bitmap与mat互转方便opencv操作

Posted 西瓜6

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bitmap与mat互转方便opencv操作相关的知识,希望对你有一定的参考价值。

bitmap与mat互转方便opencv操作

前言

老实说接下来要说的有点复杂,甚至还有可能不够特别详细。所以哪里有不懂的,可以在这篇博客下留言,我也会及时回复留言和修改这篇博客。
开发工具是android studio,达到的效果是在java层中输入bitmap,在c++层里将bitmap转为mat,然后用opencv来进行图像处理,最后将处理好的mat再转为bitmap给到java层。

正文

首先说下需要有哪些文件,一个java文件,一个cpp文件,一个CMakeLists.txt。

cpp文件怎么写

这个cpp文件怎么写是个大难点,因为如果你本身会使用JNI调用c++代码,那么你应该只要看这一部分就好。代码我也是从别的地方复制来的,然后运行没有报错。

#include <jni.h>
#include <string>
#include <android/log.h>
#include <opencv2/opencv.hpp>
#include <android/bitmap.h>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

#undef  LOG_TAG
#define LOG_TAG "xigua6---[native]: "
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG  , LOG_TAG, __VA_ARGS__)


void BitmapToMat2(JNIEnv *env, jobject& bitmap, Mat& mat, jboolean needUnPremultiplyAlpha) 
    AndroidBitmapInfo info;
    void *pixels = 0;
    Mat &dst = mat;

    try 
        //LOGD("nBitmapToMat");
        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(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
        CV_Assert(pixels);
        dst.create(info.height, info.width, CV_8UC4);
        if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) 
            //LOGD("nBitmapToMat: RGBA_8888 -> CV_8UC4");
            Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if (needUnPremultiplyAlpha) cvtColor(tmp, dst, COLOR_mRGBA2RGBA);
            else tmp.copyTo(dst);
         else 
            // info.format == ANDROID_BITMAP_FORMAT_RGB_565
            //LOGD("nBitmapToMat: RGB_565 -> CV_8UC4");
            Mat tmp(info.height, info.width, CV_8UC2, pixels);
            cvtColor(tmp, dst, COLOR_BGR5652RGBA);
        
        AndroidBitmap_unlockPixels(env, bitmap);
        return;
     catch (const cv::Exception &e) 
        AndroidBitmap_unlockPixels(env, bitmap);
        //LOGE("nBitmapToMat catched cv::Exception: %s", e.what());
        jclass je = env->FindClass("org/opencv/core/CvException");
        if (!je) je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return;
     catch (...) 
        AndroidBitmap_unlockPixels(env, bitmap);
        //LOGE("nBitmapToMat catched unknown exception (...)");
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code nBitmapToMat");
        return;
    


void BitmapToMat(JNIEnv *env, jobject& bitmap, Mat& mat) 
    BitmapToMat2(env, bitmap, mat, false);


void MatToBitmap2
        (JNIEnv *env, Mat& mat, jobject& bitmap, jboolean needPremultiplyAlpha) 
    AndroidBitmapInfo info;
    void *pixels = 0;
    Mat &src = mat;

    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) 
            Mat tmp(info.height, info.width, CV_8UC4, pixels);
            if (src.type() == CV_8UC1) 
                //LOGD("nMatToBitmap: CV_8UC1 -> RGBA_8888");
                cvtColor(src, tmp, COLOR_GRAY2RGBA);
             else if (src.type() == CV_8UC3) 
                //LOGD("nMatToBitmap: CV_8UC3 -> RGBA_8888");
                cvtColor(src, tmp, COLOR_RGB2RGBA);
             else if (src.type() == CV_8UC4) 
                //LOGD("nMatToBitmap: CV_8UC4 -> RGBA_8888");
                if (needPremultiplyAlpha)
                    cvtColor(src, tmp, COLOR_RGBA2mRGBA);
                else
                    src.copyTo(tmp);
            
         else 
            // info.format == ANDROID_BITMAP_FORMAT_RGB_565
            Mat tmp(info.height, info.width, CV_8UC2, pixels);
            if (src.type() == CV_8UC1) 
                //LOGD("nMatToBitmap: CV_8UC1 -> RGB_565");
                cvtColor(src, tmp, COLOR_GRAY2BGR565);
             else if (src.type() == CV_8UC3) 
                //LOGD("nMatToBitmap: CV_8UC3 -> RGB_565");
                cvtColor(src, tmp, COLOR_RGB2BGR565);
             else if (src.type() == CV_8UC4) 
                //LOGD("nMatToBitmap: CV_8UC4 -> RGB_565");
                cvtColor(src, tmp, COLOR_RGBA2BGR565);
            
        
        AndroidBitmap_unlockPixels(env, bitmap);
        return;
     catch (const cv::Exception &e) 
        AndroidBitmap_unlockPixels(env, bitmap);
        //LOGE("nMatToBitmap catched cv::Exception: %s", e.what());
        jclass je = env->FindClass("org/opencv/core/CvException");
        if (!je) je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return;
     catch (...) 
        AndroidBitmap_unlockPixels(env, bitmap);
        //LOGE("nMatToBitmap catched unknown exception (...)");
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code nMatToBitmap");
        return;
    


void MatToBitmap(JNIEnv *env, Mat& mat, jobject& bitmap) 
    MatToBitmap2(env, mat, bitmap, false);


extern "C"
JNIEXPORT void JNICALL
Java_xxx_xxx_xxx_antiAliasing(JNIEnv *env,
                                                          jobject jobj,
                                                          jobject jsrcBitmap1,
                                                          jobject jsrcBitmap2
                                                          )
    LOGD("start");
    Mat mat_image_src1,mat_image_src2;
    BitmapToMat(env,jsrcBitmap1,mat_image_src1);//(224结果)图片转化成mat
    LOGD("bitmap2mat small finish");
    Mat img_alpha1,img_alpha2;
    std::vector<Mat>mv1,mv2;
    split(mat_image_src1, mv1);
    LOGD("split small finish");
    img_alpha1=mv1[3];
    cv::resize(img_alpha1, img_alpha2, cv::Size(1920, 1080),INTER_CUBIC);
    LOGD("resize finish");
    cv::threshold(img_alpha2, img_alpha2, 200, 255, THRESH_BINARY);
    LOGD("threshold finish");
    cv::blur(img_alpha2, img_alpha2, Size(7,7));
    LOGD("Blur finish");
    //merge
    Mat mat_image_dst2;
    LOGD("channels %d\\n", img_alpha2.channels());
    mv2.push_back(img_alpha2);
    mv2.push_back(img_alpha2);
    mv2.push_back(img_alpha2);
    mv2.push_back(img_alpha2);
    LOGD("m2 finish");
    cv::merge(mv2, mat_image_dst2);
    LOGD("merge finish");
    MatToBitmap(env,mat_image_dst2,jsrcBitmap2);//mat转成化图片
    LOGD("mat2bitmap large finish");
    LOGD("finish");

其中xxx是路径哈,这个是我随便写的一个bitmap_1转mat,然后用opencv对这个mat做一个简单的resize和滤波,最后再将这个mat转为bitmap_2。

java文件与CMakeLists.txt怎么写

java一定要加的是三句
第一句

static 
    System.loadLibrary("native-lib");

这里的native-lib是上面cpp的名字(native-lib.cpp),你的的cpp文件如果是xxx.cpp,那么这里面就是System.loadLibrary(“xxx”);

第二句

public native void antiAliasing(Bitmap bitmap1,Bitmap bitmap2);

也就是声明这个函数

第三句

antiAliasing(rgbFrame224_224,rgbFrame1920_1080);

也就是使用这个函数

而在CMakeLists.txt则是根据情况自己改,我把我的CMakeLists.txt粘出来,也可以照着参考着写一下哈。

# Sets the minimum version of CMake required to build your native library.
# This ensures that a certain set of CMake features is available to
# your build.

cmake_minimum_required(VERSION 3.4.1)

# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
# define multiple libraries by adding multiple add.library() commands,
# and CMake builds them for you. When you build your app, Gradle
# automatically packages shared libraries with your APK.

add_library(libopencv_world SHARED IMPORTED)
add_library(libtbb SHARED IMPORTED)
add_library(libopencv_img_hash SHARED IMPORTED)

add_library( # Specifies the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        src/main/cpp/native-lib.cpp )


# Specifies a path to native header files.
include_directories($CMAKE_SOURCE_DIR/src/main/cpp/include/)
include_directories($CMAKE_SOURCE_DIR/src/main/cpp/)
set_target_properties(libopencv_world PROPERTIES IMPORTED_LOCATION
        $CMAKE_SOURCE_DIR/src/main/jniLibs/$ANDROID_ABI/libopencv_world.so)

set_target_properties(libtbb PROPERTIES IMPORTED_LOCATION
        $CMAKE_SOURCE_DIR/src/main/jniLibs/$ANDROID_ABI/libtbb.so)

set_target_properties(libopencv_img_hash PROPERTIES IMPORTED_LOCATION
        $CMAKE_SOURCE_DIR/src/main/jniLibs/$ANDROID_ABI/libopencv_img_hash.so)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-lib
        libopencv_world
        libtbb
        libopencv_img_hash
        jnigraphics
        # Links the target library to the log library
        # included in the NDK.

        $log-lib )

结束语

亲测可用,然后哪里有报错改哪里就行。
嘿嘿,有帮助就点个赞和关注咯。感谢各位。

以上是关于bitmap与mat互转方便opencv操作的主要内容,如果未能解决你的问题,请参考以下文章

bitmap与mat互转方便opencv操作

opencv QImage与Mat 互转 及简单的图像处理

OpenCV Mat和Uchar互转

opencv中Mat类型数据操作与遍历

OpenCV入门教程-Mat类之选取图像局部区域

用于 OpenCv C++ 中像素像素操作的 Mat 与数组