SkillAgentSearch skills...

AndroidOpenCVDemo

Demo for using opencv and vlfeat in android

Install / Use

/learn @WideLee/AndroidOpenCVDemo
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Android中编译以及使用OpenCV

Created By MingkuanLi On 2017-09-26

1. 概述

项目中需要在Android中使用OpenCV中图像处理,提取特征点等功能,于是折腾了很久,从最开始的Eclipse+Android.mk的方式编译把OpenCV集成到Android项目中,到后来Android Studio支持NDK开发,使用cmake构建项目的native部分,发现其实在Android中使用OpenCV并不是一件特别困难的事情,参考如下过程可以快速搭建起工程环境。

下边使用的OpenCV版本是2.4,对于OpenCV 3以上,可能还有些不一样,具体编译等可以参考这个博客。

2. 直接使用OpenCV for Android

  • 在OpenCV官网这里可以下载到AndroidSDK,并且里面有一篇教程,不过是针对Eclipse的,并且最原始的版本需要另外安装一个OpenCV Loader类似的应用才能使用。
  • 下载下来的OpenCV android sdk目录结构大概如下所示,主要使用的是sdk目录
    • java目录包括SDK的Eclilpse工程,把这个工程导入到项目中后就可以使用OpenCV提供的Java API
    • native目录主要是C++的头文件以及针对于各种移动CPU架构的动态/静态链接库
OpenCV-2.4.13-android-sdk
|_ doc
|_ samples
|_ sdk
|    |_ etc
|    |_ java
|    |_ native
|          |_ 3rdparty
|          |_ jni
|          |_ libs
|               |_ armeabi
|               |_ armeabi-v7a
|               |_ x86
|
|_ LICENSE
|_ README.android
  • 新建一个Android工程,勾选C++ support,如下图所示:

创建工程

  • 在项目那里右键打开Module Setting,导入sdk目录中的java文件夹,即OpenCV的Java API,如果项目中只需要在C++中使用OpenCV,那么不需要导入这一步

导入OpenCV的Java API

  • 把OpenCV中native中jni的include目录以及libs目录复制到工程项目内,这里放到了app/libs/opencv/include以及app/libs/opencv/libs
  • 修改build.gradle
    • 通过abiFilters指定要编译的CPU架构
    • 通过jniLibs.srcDirs指定要加载的库的路径(如果不指定可能会出现找不到某个函数实现的错误)
apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "indoor.sysu.mobile.limk.opencvtest"
        minSdkVersion 19
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions"
            }
        }
      	ndk {
            abiFilters 'armeabi-v7a'
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs/opencv/libs']
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}
  • **(重要)**修改CMakeList.txt
    • 通过set(name "value")设置变量可以供CMakeList后面使用
    • 通过include_directories()设置include的路径,使用${CMAKE_SOURCE_DIR}指定相对路径
    • add_library(libopencv_java SHARED IMPORTED )通过SHARED指定.so文件的动态链接库
    • add_library(libopencv_calib3d STATIC IMPORTED )通过STATIC指定各种.a静态链接库
    • set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fexceptions -frtti")设置g++编译时候的参数
    • 项目里要编译的库的名字为native-lib,最后通过target_link_libraries()添加opencv相关的链接库
cmake_minimum_required(VERSION 3.6)

set(CMAKE_VERBOSE_MAKEFILE on)

set(libs "${CMAKE_SOURCE_DIR}/libs/opencv/libs")

include_directories(${CMAKE_SOURCE_DIR}/libs/opencv/include)

add_library(libopencv_java SHARED IMPORTED )
set_target_properties(libopencv_java PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_java.so")

add_library(libopencv_calib3d STATIC IMPORTED )
set_target_properties(libopencv_calib3d PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_calib3d.a")

add_library(libopencv_contrib STATIC IMPORTED )
set_target_properties(libopencv_contrib PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_contrib.a")

add_library(libopencv_core STATIC IMPORTED )
set_target_properties(libopencv_core PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_core.a")

add_library(libopencv_features2d STATIC IMPORTED )
set_target_properties(libopencv_features2d PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_features2d.a")

add_library(libopencv_flann STATIC IMPORTED )
set_target_properties(libopencv_flann PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_flann.a")

add_library(libopencv_highgui STATIC IMPORTED )
set_target_properties(libopencv_highgui PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_highgui.a")

add_library(libopencv_imgproc STATIC IMPORTED )
set_target_properties(libopencv_imgproc PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_imgproc.a")

add_library(libopencv_legacy STATIC IMPORTED )
set_target_properties(libopencv_legacy PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_legacy.a")

add_library(libopencv_ml STATIC IMPORTED )
set_target_properties(libopencv_ml PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_ml.a")

add_library(libopencv_objdetect STATIC IMPORTED )
set_target_properties(libopencv_objdetect PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_objdetect.a")

add_library(libopencv_photo STATIC IMPORTED )
set_target_properties(libopencv_photo PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_photo.a")

add_library(libopencv_stitching STATIC IMPORTED )
set_target_properties(libopencv_stitching PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_stitching.a")

add_library(libopencv_superres STATIC IMPORTED )
set_target_properties(libopencv_superres PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_superres.a")

add_library(libopencv_video STATIC IMPORTED )
set_target_properties(libopencv_video PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_video.a")

add_library(libopencv_videostab STATIC IMPORTED )
set_target_properties(libopencv_videostab PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_videostab.a")

add_library(libopencv_ts STATIC IMPORTED )
set_target_properties(libopencv_ts PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_ts.a")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fexceptions -frtti")

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).
             # Associated headers in the same location as their source
             # file are automatically included.
             src/main/cpp/native-lib.cpp)

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(native-lib android log
    libopencv_java
    libopencv_calib3d
    libopencv_contrib
    libopencv_core
    libopencv_features2d
    libopencv_flann
    libopencv_highgui
    libopencv_imgproc
    libopencv_legacy
    libopencv_ml
    libopencv_objdetect
    libopencv_photo
    libopencv_stitching
    libopencv_superres
    libopencv_video
    libopencv_videostab
    libopencv_ts
    ${log-lib}
    )
  • native-lib.cpp中编写测试代码
#include <jni.h>
#include <string>
#include "opencv2/opencv.hpp"

extern "C"
JNIEXPORT jstring JNICALL
Java_indoor_sysu_mobile_limk_opencvtest_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    char hello[100] = {"Hello from JNI"};
    cv::Mat mat = cv::imread("/sdcard/test.jpeg", CV_LOAD_IMAGE_COLOR);
    char spec[20] = {};
    sprintf(spec, ", image size: %d x %d", mat.rows, mat.cols);
    strcat(hello, spec);

    return env->NewStringUTF(hello);
}
  • MainActivity.java中加载opencv_java动态链接库以及native-lib链接库
package indoor.sysu.mobile.limk.opencvtest;

import android.Manifest;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("opencv_java");
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());

        checkPermission();
    }

    @TargetApi(Build.VERSION_CODES.M)
    private void checkPermission() {
        if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0x10);
        }
    }

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

  • 测试是否能正确编译运行(读写存储卡中的图片记得动态申请读写外部存储的权限),下图所示能正确读出给定图片的大小

运行结果-1


  • 下面使用opencv提取SURF特征点,由于SURF模块属于opencvnonfree的模块,所以在官方提供的opencv for android sdk中并没有提供这个模块的内容,如果不想折腾想迅速搭建起环境,可以使用我编译好的nonfree模块
  • 下载这个动态链接库,放到libs/opencv/libs/armeabi-v7a/目录下
  • 下载这个头文件,解压放到libs/opencv/include/opencv2/nonfree目录
  • CMakeList.txt中添加如下加载动态链接库
add_library(libopencv_nonfree SHARED IMPORTED )
set_target_properties(libopencv_nonfree PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libnonfree.so")

// something...

target_link_libraries(native-lib android log
    libopencv
View on GitHub
GitHub Stars4
CategoryDevelopment
Updated3y ago
Forks1

Languages

C++

Security Score

55/100

Audited on Mar 3, 2023

No findings