OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。
-------------------------------------------------我是罪恶的分割线------------------------------------------------------
配置方式有三种,第一种是jni静态链接库,第二种是jni动态链接库,第三种是java sdk,本次只介绍第一二种,下面我们开始android开发环境的搭建:
示例环境:JDK1.8、NDK-r14b、Android Studio 2.3.2、 OpenCV-android-sdk-3.2
一、搭建NDK环境
ndk在搭建非常简单,不作过多描述,截图说话;
到这里NDK环境搭建完成。
二、使用OpenCV开源库
1、下载OpenCV开源库并解压 链接:opencv-3.2.0-android-sdk
2、将解压后的文件目录中的sdk文件夹下的native文件夹拷贝至新建工程中的jni文件夹下,如下图:
3、下面用一个图片灰度化的例子来做代码演示
public class OpenCVHelper {
static {
System.loadLibrary("OpenCV");
}
public static native int[] gray(int[] buf, int w, int h);
}
4、使用javah命令在main文件夹目录下自动生成 .h头文件
javah -jni “包名”+.opencv.OpenCVHelper
#include "com_example_helloopencv_opencv_OpenCVHelper.h"
#include
#include
#include
using namespace cv;
extern "C" {
JNIEXPORT jintArray JNICALL Java_com_example_helloopencv_opencv_OpenCVHelper_gray(
JNIEnv *env, jclass obj, jintArray buf, int w, int h);
JNIEXPORT jintArray JNICALL Java_com_example_helloopencv_opencv_OpenCVHelper_gray(
JNIEnv *env, jclass obj, jintArray buf, int w, int h) {
jint *cbuf;
cbuf = env->GetIntArrayElements(buf, JNI_FALSE);
if (cbuf == NULL) {
return 0;
}
Mat imgData(h, w, CV_8UC4, (unsigned char *) cbuf);
uchar *ptr = imgData.ptr(0);
for (int i = 0; i < w * h; i++) {
//计算公式:Y(亮度) = 0.299*R + 0.587*G + 0.114*B
//对于一个int四字节,其彩色值存储方式为:BGRA
int grayScale = (int) (ptr[4 * i + 2] * 0.299 + ptr[4 * i + 1] * 0.587 +
ptr[4 * i + 0] * 0.114);
ptr[4 * i + 1] = grayScale;
ptr[4 * i + 2] = grayScale;
ptr[4 * i + 0] = grayScale;
}
int size = w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result, 0, size, cbuf);
env->ReleaseIntArrayElements(buf, cbuf, 0);
return result;
}
}
Application.mk
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-8
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OpenCV_INSTALL_MODULES := on
OpenCV_CAMERA_MODULES := off
OPENCV_LIB_TYPE :=STATIC
ifeq ("$(wildcard $(OPENCV_MK_PATH))","")
include ..\..\..\..\app\src\main\jni\native\jni\OpenCV.mk
else
include $(OPENCV_MK_PATH)
endif
LOCAL_MODULE := OpenCV
LOCAL_SRC_FILES := com_example_helloopencv_opencv_OpenCVHelper.cpp
LOCAL_LDLIBS += -lm -llog
include $(BUILD_SHARED_LIBRARY)
app/build.gradle,在android中添加
//禁止自带的ndk功能
sourceSets.main.jni.srcDirs = []
task ndkBuild(type: Exec, description: 'Compile JNI source with NDK') {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkDir = properties.getProperty('ndk.dir')
if (org.apache.tools.ant.taskdefs.condition.Os.isFamily(org.apache.tools.ant.taskdefs.condition.Os.FAMILY_WINDOWS)) {
commandLine "$ndkDir/ndk-build.cmd", '-C', file('src/main/jni').absolutePath
} else {
commandLine "$ndkDir/ndk-build", '-C', file('src/main/jni').absolutePath
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
task ndkClean(type: Exec, description: 'Clean NDK Binaries') {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkDir = properties.getProperty('ndk.dir')
if (org.apache.tools.ant.taskdefs.condition.Os.isFamily(org.apache.tools.ant.taskdefs.condition.Os.FAMILY_WINDOWS)) {
commandLine "$ndkDir/ndk-build.cmd", 'clean', '-C', file('src/main/jni').absolutePath
} else {
commandLine "$ndkDir/ndk-build", 'clean', '-C', file('src/main/jni').absolutePath
}
}
clean.dependsOn 'ndkClean'
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
7、通过ndkBuild生成.so文件,点击右边栏Gradle中app-->Tasks-->other-->ndkBuild ,自动生成libs、obj文件夹
8、将main/libs的文件复制到app/libs文件中,在
9、在MainActivity中使用gray方法处理图片
public class MainActivity extends Activity {
ImageView img;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView) findViewById(R.id.img_view);
Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.mipmap.ic_launcher)).getBitmap();
int w = bitmap.getWidth(), h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int [] resultPixes= OpenCVHelper.gray(pix,w,h);
Bitmap result = Bitmap.createBitmap(w,h, Bitmap.Config.RGB_565);
result.setPixels(resultPixes, 0, w, 0, 0,w, h);
img.setImageBitmap(result);
}
}
三、配置中出现问题及解答
1、Error:Execution failed for task ':app:ndkBuild'.
> Process 'command 'C:\Users\longx\AppData\Local\Android\Sdk\ndk-bundle/ndk-build.cmd'' finished with non-zero exit value 2
解答:cpp文件报错的同时,说明opencv2不再同一个包中,需要把native文件夹放在jni文件夹目录下,犯这个错误的原因是配置的时候参考了一些博客上错误的描述导致的。
2、 FATAL EXCEPTION: main
Process: com.jacksparrow.hellohumens, PID: 18913
java.lang.UnsatisfiedLinkError: No implementation found for int[] com.jacksparrow.hellohumens.opencv.OpenCVHelper.gray(int[], int, int) (triedJava_com_example_helloopencv_opencv_OpenCVHelper_gray and Java_com_example_helloopencv_opencv_OpenCVHelper_gray___3III)
at com.example_helloopencv.opencv.OpenCVHelper.gray(Native Method)
at com.example_helloopencv.MainActivity.onCreate(MainActivity.java:24)
解答:从提示信息中看出gray方法没有找到,也就说明.so文件中没有该方法的调用。分析是查看Android.mk文件时,发现“LOCAL_SRC_FILES :=”并没有把cpp文件编译进去,故加上cpp文件为:“LOCAL_SRC_FILES := com_example_helloopencv_opencv_OpenCVHelper.cpp”
四、拓展配置:jni动态库(区别:生成的.so文件会小好几倍)
1、修改Android.mk文件中的“OPENCV_LIB_TYPE”的值从“STATIC”改为“SHARED”。
2、将native/libs中各个文件夹的libopencv_java3.so文件放到main/libs中对应的各个文件夹中。