复制目录opencv-4.6.0-android-sdk\OpenCV-android-sdk\sdk\native\jni的include文件夹,和opencv-4.6.0-android-sdk\OpenCV-android-sdk\sdk\native\libs\armeabi-v7a目录对应的cpu架构类型.项目没有对应目录,手动创建一下.
可以参考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
)
参考github OpenCV ,实现图片灰度转换
先写一个bitmap转mat工具类
utils.hpp
//
// Created by moyihen on 2022/8/17.
//
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#ifdef __ANDROID__
#include
#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
#include
#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
)