AndroidStudio OpenCV NDK tutorial

简介

  • OpenCV是目前计算机视觉里面非常常用的一个开源库,支持各大平台

准备条件

  • AndroidStudio 最新版本
  • SDK Manager里面安装SDK, NDK
  • OpenCV 3.4/4.0
    1
    wget https://codeload.github.com/OpenCV/OpenCV/zip/3.4.6

准备知识-CMake

AndroidStudio 支持cmake编译C/C++文件,通过编写CMakeList.txt来实现

常用变量

1
2
${CMAKE_SOURCE_DIR} # CMakeLists.txt文件所在位置
${ANDROID_ABI} # Android ABI架构 ("armeabi-v7a","arm64-v8a")

常用函数

  • 常用指令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # Set project
    project(demo)
    # Set variable
    set(VARIABLE, VALUE)
    # Show message
    message(${ANDROID_ABI})
    # if else
    if(${ANDROID_ABI} STREQUAL "areambi")
    message("armv5")
    elseif(${ANDROID_ABI} STREQUAL "areambi-v7a")
    message("armv7a")
    elseif(${ANDROID_ABI} STREQUAL "arm64-v8a")
    message("armv8a")
    elseif(${ANDROID_ABI} STREQUAL "x86_64")
    message("x86_64")
    elseif(${ANDROID_ABI} STREQUAL "x86")
    message("x86")
    else()
    message("unknown abi")
    endif()
  • 添加共享库

    1
    2
    3
    4
    5
    6
    7
    add_library( 
    # Sets 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)
  • 添加可执行文件

    1
    2
    3
    4
    5
    add_executable( 
    # Sets the name of the executable file.
    test
    # Provides a relative path to your source file(s).
    src/main/cpp/main.cpp)
  • 查找NDK library

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 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)
  • 指定链接库

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 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.
    test
    # Links the target library to the log library
    # included in the NDK.
    ${log-lib})
  • 指定包含头文件

    1
    2
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/)
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/OpenCV)
  • 手动指定共享库

    1
    2
    3
    add_library(libOpenCV_java3 SHARED IMPORTED)
    set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION
    ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.so)
  • 查找所有源文件,并保存到IR_SRCS变量,但是不能查找子目录

    1
    aux_source_directory(${CMAKE_SOURCE_DIR}/src/main/cpp DIR_SRCS)

编译器设置

我们可以在CMakeLists.txt里面设置编译器参数,也可以在build.gradle脚本里面设置

  • CMakeLists.txt 设置

    1
    2
    3
    #支持-std=gnu++11
    set(CMAKE_VERBOSE_MAKEFILE on)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
  • build.gradle 脚本设置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    apply plugin: 'com.android.application'

    android {
    defaultConfig {
    externalNativeBuild {
    cmake {
    //设置cpp Flags
    cppFlags "-std=c++11 -frtti -fexceptions"
    //设置STL共享库,这里要注意,部分Android系统里面可能没有libc++_shared.so,这个时候需要在app里面打包进去
    //文件路径在NDK安装目录下 sources/cxx-stl/llvm-libc++/libs/${ANDROID_ABI}/libc++_shared.so
    arguments "-DANDROID_STL=c++_shared"
    }
    }
    }
    }

输出设置

  • 动态共享库 .so

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/OpenCV)
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/)
    add_library(libOpenCV_java3 SHARED IMPORTED)
    set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION
    ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.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)
    add_library( # Sets 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)
    target_link_libraries( # Specifies the target library.
    native-lib
    libOpenCV_java3
    # Links the target library to the log library
    # included in the NDK.
    ${log-lib})
  • 静态共享库 .a

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/OpenCV)
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/)
    add_library(libOpenCV_java3 SHARED IMPORTED)
    set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION
    ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.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)
    add_library( # Sets the name of the library.
    native-lib

    # Sets the library as a static library.
    STATIC

    # Provides a relative path to your source file(s).

    src/main/cpp/native-lib.cpp)
    target_link_libraries( # Specifies the target library.
    native-lib
    libOpenCV_java3
    # Links the target library to the log library
    # included in the NDK.
    ${log-lib})
  • Executable

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/OpenCV)
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/)
    add_library(libOpenCV_java3 SHARED IMPORTED)
    set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION
    ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.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)
    # 设置可执行文件的输出目录
    set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/src/main/assets/${ANDROID_ABI}")
    # 添加可执行文件的源文件
    add_executable(
    test

    src/main/cpp/main.cpp
    )
    target_link_libraries( # Specifies the target library.
    test
    libOpenCV_java3
    # Links the target library to the log library
    # included in the NDK.
    ${log-lib})

依赖设置

与Gradle结合

新建Project

用AndroidStudio创建项目,并选择Native C++支持

导入OpenCV头文件

  1. src/main/cpp目录下创建include目录
  2. 将OpenCV SDK解压后,sdk/native/jni/include/目录下的两个头文件文件夹OpenCV, OpenCV2复制到上面创建的include目录下
  3. CMakeList.txt添加对应引用
    1
    include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include/)

导入OpenCV so库

  1. 创建src/main/jniLibs目录,用于存放第三方共享库
  2. 将OpenCV SDK解压后,sdk/native/libs/目录下的so文件文件夹复制到上面创建的jniLibs目录下,这些文件夹是以abi为目录保存的。
  3. CMakeList.txt添加对应依赖
    1
    2
    3
    add_library(libOpenCV_java3 SHARED IMPORTED)
    set_target_properties(libOpenCV_java3 PROPERTIES IMPORTED_LOCATION
    ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libOpenCV_java3.so)

jni引用OpenCV方法

1
2
3
#include "OpenCV2/core.hpp"
using namespace cv;

编译验证