Android:OpenCV学习日记(一)-- 环境搭建

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在搭建非常简单,不作过多描述,截图说话;

Android:OpenCV学习日记(一)-- 环境搭建_第1张图片

Android:OpenCV学习日记(一)-- 环境搭建_第2张图片

Android:OpenCV学习日记(一)-- 环境搭建_第3张图片

Android:OpenCV学习日记(一)-- 环境搭建_第4张图片

Android:OpenCV学习日记(一)-- 环境搭建_第5张图片

到这里NDK环境搭建完成。


二、使用OpenCV开源库

1、下载OpenCV开源库并解压  链接:opencv-3.2.0-android-sdk

2、将解压后的文件目录中的sdk文件夹下的native文件夹拷贝至新建工程中的jni文件夹下,如下图:

Android:OpenCV学习日记(一)-- 环境搭建_第6张图片

3、下面用一个图片灰度化的例子来做代码演示

Android:OpenCV学习日记(一)-- 环境搭建_第7张图片

public class OpenCVHelper {
    static {
        System.loadLibrary("OpenCV");
    }
    public static native int[] gray(int[] buf, int w, int h);
}
4、使用javah命令在main文件夹目录下自动生成 .h头文件

Android:OpenCV学习日记(一)-- 环境搭建_第8张图片

javah -jni “包名”+.opencv.OpenCVHelper


5、新建并编辑cpp文件,命名与自动生成的h头文件相同,添加如下内容(图片灰度化代码), 注:下面代码第1行,引进h头文件的名称为自动生成的名称,第10、13行名称也许注意

#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;
    }
}

6、在jni目录下新建Application.mk 、Android.mk 文件

Application.mk

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-8

Android.mk
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文件夹

Android:OpenCV学习日记(一)-- 环境搭建_第9张图片
Android:OpenCV学习日记(一)-- 环境搭建_第10张图片

8、将main/libs的文件复制到app/libs文件中,在

Android:OpenCV学习日记(一)-- 环境搭建_第11张图片


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);
    }
}

10、运行app,得到结果如下图:

Android:OpenCV学习日记(一)-- 环境搭建_第12张图片


三、配置中出现问题及解答

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

Android:OpenCV学习日记(一)-- 环境搭建_第13张图片

Android:OpenCV学习日记(一)-- 环境搭建_第14张图片

解答: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中对应的各个文件夹中。


你可能感兴趣的:(Android,android,openCV,OpenCV4Android,OpenCV配置,OpenCV,Android,Studio,配置Ope)