Android集成OpenCV(NDK)

(转载请删除括号里的内容)

1.下载OpenCv的动态库(.so)

OpenCv官网,这边下载的是4.6.0
在这里插入图片描述

2.解压opencv-4.6.0-android-sdk.zip

复制目录opencv-4.6.0-android-sdk\OpenCV-android-sdk\sdk\native\jniinclude文件夹,和opencv-4.6.0-android-sdk\OpenCV-android-sdk\sdk\native\libs\armeabi-v7a目录对应的cpu架构类型.项目没有对应目录,手动创建一下.
在这里插入图片描述

3.配置CMakeLists

可以参考Android NDK项目CMakeLists.txt配置导入第三方库

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.18.1)

# Declares and names the project.

project("mnnmyh")

aux_source_directory(. SRC_LIST) # 当前文件夹下的所有文件,不包含子文件夹
add_library( # Sets the name of the library.
        mnnmyh
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s).
        #native-lib.cpp)
        ${SRC_LIST})
        
#opencv
include_directories(${CMAKE_SOURCE_DIR}/opencv/include/)
add_library(libopencv_java4 SHARED IMPORTED)
set_target_properties(
        libopencv_java4
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_java4.so)


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)

target_link_libraries( # Specifies the target library.
        mnnmyh
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib}
        #jnigraphics库可以用来从android.bitmap.Graphics类 访问C / C ++中的位图缓冲区
        jnigraphics
        libopencv_java4
        )

4.测试OpenCV是否配置正常

参考github OpenCV ,实现图片灰度转换
先写一个bitmap转mat工具类
utils.hpp

//
// Created by moyihen on 2022/8/17.
//

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"

#ifdef __ANDROID__

#include <android/bitmap.h>
#include "android/log.h"

#define TAG "org.opencv.android.Utils"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
using namespace cv;

void BitmapToMat(JNIEnv *env, jobject bitmap, Mat &dst, jboolean needUnPremultiplyAlpha) {
    AndroidBitmapInfo info;
    void *pixels = 0;
    try {
        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 caught cv::Exception: %s", e.what());
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return;
    } catch (...) {
        AndroidBitmap_unlockPixels(env, bitmap);
        LOGE("nBitmapToMat caught unknown exception (...)");
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {nBitmapToMat}");
        return;
    }
}
void MatToBitmap(JNIEnv *env, Mat &src, jobject bitmap, jboolean 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) {
            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 caught cv::Exception: %s", e.what());
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, e.what());
        return;
    } catch (...) {
        AndroidBitmap_unlockPixels(env, bitmap);
        LOGE("nMatToBitmap caught unknown exception (...)");
        jclass je = env->FindClass("java/lang/Exception");
        env->ThrowNew(je, "Unknown exception in JNI code {nMatToBitmap}");
        return;
    }
}
#endif //__ANDROID__

nativ方法实现
native-lib.cpp

#include <jni.h>
#include <string>
#include "utils.hpp"

extern "C"
JNIEXPORT jstring JNICALL
Java_com_moyihen_mnnmyh_JniBitmapUtil_stringFromJNI(JNIEnv *env, jclass clazz) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}



extern "C"
JNIEXPORT void JNICALL
Java_com_moyihen_mnnmyh_JniBitmapUtil_coverImg2Gray(JNIEnv *env, jclass clazz, jobject bitmap) {
    //源图像
    Mat src;
    //将Bitmap转换为Mat
    BitmapToMat(env,bitmap,src, JNI_FALSE);

    //转换的灰度图
    Mat gray_image;
    cvtColor(src, gray_image, COLOR_BGR2GRAY );

    //将Mat转换为Bitmap
    MatToBitmap(env,gray_image,bitmap, JNI_FALSE);

    //释放Mat
    src.release();
    gray_image.release();
}
import android.graphics.Bitmap;

public class JniBitmapUtil {
    // Used to load the 'mnnmyh' library on application startup.
    static {
        System.loadLibrary("mnnmyh");
    }

    /**
     * A native method that is implemented by the 'mnnmyh' native library,
     * which is packaged with this application.
     */
    public static native String stringFromJNI();

    public static native void coverImg2Gray(Bitmap bitmap);
}

调用

 mCvBinding.button.setOnClickListener(v -> {
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.hzw);
            JniBitmapUtil.coverImg2Gray(bitmap);

            mCvBinding.img2.setImageBitmap(bitmap);

        });

效果
在这里插入图片描述

注意:调试的时候出现几个问题,可以参考下
1. dlopen failed: library “libc++_shared.so” not found
在这里插入图片描述
需在在app的build.gradle配置arguments “-DANDROID_STL=c++_shared”

defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags '-std=c++11'
                arguments "-DANDROID_STL=c++_shared"
            }
        }
    }

2.error: undefined symbol: AndroidBitmap_getInfo
在这里插入图片描述
需要在CMakeLists.txt的target_link_libraries 加上jnigraphics

target_link_libraries( # Specifies the target library.
        mnnmyh
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib}
        #jnigraphics库可以用来从android.bitmap.Graphics类 访问C / C ++中的位图缓冲区
        jnigraphics
        libopencv_java4
        )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Android项目中集成OpenCV,需要进行以下步骤: 1. 下载OpenCV Android SDK,可以从OpenCV官网上下载。将下载的压缩包解压到任意目录。 2. 在Android Studio中创建一个新项目,然后将解压后的OpenCV Android SDK目录中的opencv库文件夹复制到项目的根目录下。 3. 在项目的build.gradle文件中添加以下代码: ``` android { ... defaultConfig { ... ndk { abiFilters "armeabi-v7a", "x86" } externalNativeBuild { cmake { cppFlags "-frtti -fexceptions" arguments "-DANDROID_STL=c++_shared" } } } ... } dependencies { ... implementation project(':opencv') ... } ``` 4. 在项目的settings.gradle文件中添加以下代码: ``` include ':app', ':opencv' project(':opencv').projectDir = new File(rootProject.projectDir, 'opencv') ``` 5. 在项目的MainActivity.java文件中加载OpenCV库文件,可以使用以下代码: ``` package com.example.myapplication; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { // OpenCV加载成功,可以进行相关操作 } break; default: { super.onManagerConnected(status); } break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (!OpenCVLoader.initDebug()) { OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, this, mLoaderCallback); } else { mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS); } } } ``` 这样,就可以在Android项目中成功集成OpenCV并使用OpenCV库文件了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值