Ubuntu 16.04下为Android编译OpenCV 3.2.0 Manager

        最近想在Android上尝试一下SIFT和SURF匹配算法,但考虑到这些算法都是专利保护的,并没有被包含在预编译库中,所以还需要自己来动手编译OpenCV Android SDK。在OpenCV 2.4.x版本中,这些算法被包含在nonfree模块中;从3.0版本开始,用于图像特征匹配的一些算法(比如SIFT,SURF,BRIEF,FREAK等)被转移到了opencv_contrib项目的xfeatures2d模块中。在PC环境下,为C++编译opencv+contrib库是很方便的,不过为Android平台的编译过程就有些麻烦了。

        我在编译的过程中也遇到了一些问题,在网络上搜索相应解决方案时也发现很多人都在尝试为OpenCV Android SDK添加contrib(nonfree)支持,某些遇到难以解决的问题最后只能绕路而行,比如这里这里。我找到相应解决办法后回应了他们,但愿对别人会有所帮助吧!

        本文要介绍的内容就是如何在Ubuntu 16.04环境下利用最新的OpenCV和opencv_contrib为Android平台编译一个可用的OpenCV Android SDK,并生成相应的OpenCV Manager。

2017.08.03更新:

        更新到OpenCV 3.2,Android SDK API 24,Android NDK r15b。

        我原本挣扎了三天尝试在Windows平台通过MinGW来编译最新版本的OpenCV Android SDK,但在生成Manager的apk时遇到很棘手的问题,只好作罢转回Linux进行编译。不过读者放心,在Linux下编译得到的OpenCV Android SDK也可在Windows下直接使用,另外我在文章结尾添加了我编译好的SDK下载链接。

        我的开发环境如下:

                Ubuntu 16.04 LTS (x64)

                GCC 5.4.0

                CMAKE 3.9.0

                OpenCV 3.2.0

                Android SDK API 24(Android 7.0)

                Android SDK Tools r25.2.2

                Androird NDK r15b

                Python 3.5

        虽然目前Android SDK Tools已经更新到r26,但由于其相对原来的工具变化较大,为了稳妥起见,建议手动降级到r25版本(下载地址:https://dl.google.com/android/repository/tools_r25.2.2-linux.zip

        当然在编译过程中还会用到很多其他工具和软件包,比如Ninja,Ant等,我会在文中需要的时候给出它们的版本和安装方法。

        关于GCC,CMAKE和Python的安装过程本文就不详述了,一是因为这些工具的安装过程很容易,网络上的介绍都很详细,二是因为之前刚刚配置好TensorFlow,安装了一大堆软件包,我也不清楚本文的内容究竟会涉及哪些依赖库,我会尽量把我在编译过程中所需的工具和库标记出来。

        同样,Android SDK和NDK的安装方法这里也不会作过多介绍。我是通过Android Studio 2.1.2提供的SDK Manager下载的Android SDK和Android NDK,在Android Studio中下载Android SDK和Android NDK的方法可以参考《Android Studio 2上利用NDK进行OpenCV 3.1开发》,虽然开发平台不同,但在软件界面中的操作过程是相似的。我的Android SDK路径是/home/john/Android/Sdk,Android NDK的路径是/home/john/Android/Sdk/ndk-bundle。


下载源码

        在opencv的master分支Release页面下载opencv 3.2源码,解压到一个有读写权限的目录下,比如/home/john/Downloads/opencv-master。在这里下载对应3.2的opencv-contrib源码,解压到某个目录下,个人习惯是解压到OpenCV的源码根目录下,使得opencv-contrib/modules目录的路径如/home/john/Downloads/opencv-master/opencv_contrib/modules,这个路径后面会用到。

个人推荐在编译其他OpenCV版本甚至编译其他软件包时要下载有版本号的Release版,而不是直接git下来最新的master版。毕竟master一般是正在开发修缮的版本,即便是整合了功能强大的CI(比如OpenCV在用的buildbot,或者其他开源库喜欢用的travis-ci)也不能保证其测试过程考虑到了大多数应用环境。

        如果你的机器上已经有了一份opencv源码,但不想花时间去下载最新版本,至少要保证你的opencv源码是在16年5月份之后下载的(具体来讲,至少要包含该Pull Request:Added –extra_modules_path to build_sdk.py #6460,这样你的build_sdk.py才会包含后面要用到的extra_modules_path)。

        仅仅下载好源码还不够,还要对源码做一些修改,具体如下:

        1.把/home/john/Downloads/opencv-master/opencv_contrib/modules/xfeatures2d/include/opencv2目录下的xfeatures2d.hpp文件和xfeatures2d文件夹复制到/home/john/Downloads/opencv-master/modules/features2d/include/opencv2目录下。此时,该目录包含的文件应该如下图所示:

features2d-include        2.找到/home/john/Downloads/opencv-master/modules/features2d/misc/java/src/cpp目录,打开features2d_manual.hpp文件,做以下修改:

        在第8行增加一个头文件opencv2/xfeatures2d.hpp,即把

改为

        把第120-125行的

改为

        把第239-245行的

改为

        把第254-256行的

改为


编译OpenCV Android SDK

        找到/home/john/Downloads/opencv-master/platforms/android目录,在该目录下会发现build_sdk.py文件,这个文件就是用来编译OpenCV Android SDK的Python脚本文件。

        首先做一些检查工作:

        1.在第78行的ABIs定义了需要编译的ABI目标以及相应的NDK工具链。保险起见,可以先在/home/john/Android/Sdk/ndk-bundle/toolchains中查看一下你的NDK工具链版本,如果版本号有所不同,就要修改build_sdk.py中对应ABI工具链的版本,如下图所示:

ndk-toolchains        mips和mips64两行被注释掉的原因是,在我的机器上编译时,由于依赖库之一Google Protobuf的编译错误,无法为这两个架构成功编译OpenCV Android SDK。不过我手边并没有采用该架构的Android设备,而且我暂时还不需要考虑短期内编写的代码有太好的兼容性,所以干脆放弃对这两种架构进行编译。如果感兴趣,你可以试着为mips编译一下:)目前在编译OpenCV 3.2版本时,所有ABI都能够成功编译(包括:arm64-v8a,armeabi,armeabi-v7a,mips,mips64,x86,x86_64)。上图并没有相应更新,还请见谅!

        2.安装Ninja。打开终端,输入:

        另外,我在编译之前参考这里又安装了几个用于交叉编译的库,不确定是否必要,但还是贴出来吧:

        其中版本号4.9根据你的NDK工具链的版本来修改(工具链路径在android-sdk\ndk-bundle\toolchains当中)。

        3.安装Ant。在终端输入:

        如果不安装Ant,在编译过程中CMAKE关于Java的输出信息全是NO,而且后面还会出现unknown target 'opencv_engine'的错误。

        4.build_sdk.py里还有很多可以根据需要来修改的地方,比如-DANDROID_NATIVE_API_LEVEL可以适当地提高,可以选择开启-DBUILD_EXAMPLES-DBUILD_TESTS等等。这里为了演示的目的,除了前文提到的,其他地方全部保持默认,不做修改。

        5.在终端中输入:

        注意命令是一行的,中间没有换行符。

        根据build_sdk.py文件中第252行的说明,其采用的参数按照以下格式:

        其中,<output-dir>是保存编译中间结果和最终结果的目录(也叫工作目录),<android-sdk-path>指向OpenCV源码目录,<android-sdk-path>为Android SDK目录,<ndk-path>为Android NDK目录,<opencv-contrib-path>为opencv_contrib/modules所在的路径。


结果

        最终,在/home/john/Downloads/opencv-master/build目录中会得到一个名为OpenCV-android-sdk的文件夹,这就是你编译得到的OpenCV Android SDK。和官方预编译库一样,在apk子文件夹中是OpenCV Manager的安装包,在sdk/java文件夹中是OpenCV的Java接口,sdk/native是OpenCV的Native接口。

        在新项目中使用自己编译的OpenCV Android SDK时,要注意需要在设备上重新安装OpenCV Manager,还要修改Android.mk中指向OpenCV.mk的路径。

opencv-manager-apk

        如果需要调用SIFT,SURF等匹配算法,还要把相应的源码文件(位于/home/john/Downloads/opencv-master/opencv_contrib/modules/xfeatures2d/src)拷贝到项目jni文件夹中,然后在Android.mk中为LOCAL_SRC_FILES添加对应的源码文件。

        在编译的过程中如果发现有错误或异常出现,可以首先比较一下OpenCV官方BuildBot的输出信息,便于分析自己的问题原因。最新编译结果的链接为:http://pullrequest.opencv.org/buildbot/one_line_per_build。一次编译成功的输出结果为precommit_pack_android Build Log #116。如果你的网络比较好,甚至可以把网站上生成的压缩包下载下来(比如这里)!

        我编译产生的OpenCV Android SDK可以在这里下载:http://pan.baidu.com/s/1kVOejLt。因为考虑到在编译过程中需要从网络下载一些文件,我已经把Linux与Windows编译所需的文件全部下载好,并和3.2的源码一同放在sources文件夹中。感兴趣的读者可以直接用这个源码包进行编译。

        另外附上一篇在Android上利用SIFT,SURF和FREAK进行目标匹配的教程:《深入OpenCV Android应用开发 中文版 – 第三章代码更新》


参考资料

[1] http://stackoverflow.com/questions/30657774/surf-and-sift-algorithms-doesnt-work-in-opencv-3-0-java

[2] https://github.com/opencv/opencv/issues/5561

[3] https://github.com/opencv/opencv/issues/6215

[4] http://answers.opencv.org/question/73863/how-to-run-build_sdkpy-for-android-sdk/

[5] https://zami0xzami.wordpress.com/2016/03/17/building-opencv-for-android-from-source/

[6] http://eevee.cc/2017/05/05/build-ocv-for-android-with-cuda/

共有18条评论

    1.  

      按照你的写法 我得到了这个东西 尝试了很多方法是在不知道怎么解决

      zhanggangmindeMacBook-Pro:android zhanggangmin$ python build_sdk.py /Users/zhanggangmin/build-opencv-for-android-master/android_opencv /Users/zhanggangmin/build-opencv-for-android-master/opencv –sdk_path=/Users/zhanggangmin/Library/Android/sdk –ndk_path=/opt/android-ndk –extra_modules_path=/Users/zhanggangmin/build-opencv-for-android-master/opencv/modules 

      Args: Namespace(build_doc=False, extra_modules_path='/Users/zhanggangmin/build-opencv-for-android-master/opencv/modules', extra_pack=None, ndk_path='/opt/android-ndk', no_ccache=False, opencv_dir='/Users/zhanggangmin/build-opencv-for-android-master/opencv', sdk_path='/Users/zhanggangmin/Library/Android/sdk', sign_with=None, work_dir='/Users/zhanggangmin/build-opencv-for-android-master/android_opencv')

      Android NDK path: /opt/android-ndk

      Android SDK path: /Users/zhanggangmin/Library/Android/sdk

      Check dir /Users/zhanggangmin/build-opencv-for-android-master/android_opencv (create: True, clean: False)

      Check dir /Users/zhanggangmin/build-opencv-for-android-master/opencv (create: False, clean: False)

      Check dir /Users/zhanggangmin/build-opencv-for-android-master/android_opencv/o4a (create: True, clean: True)

      Removing file: /Users/zhanggangmin/build-opencv-for-android-master/android_opencv/o4a/CMakeCache.txt

      Removing dir: /Users/zhanggangmin/build-opencv-for-android-master/android_opencv/o4a/CMakeFiles

      Check dir /Users/zhanggangmin/build-opencv-for-android-master/android_opencv/javadoc (create: True, clean: True)

      Check dir /Users/zhanggangmin/build-opencv-for-android-master/android_opencv/OpenCV-android-sdk (create: True, clean: True)

      Detected OpenCV version: 3.3.0-dev

      Detected Engine version: 3.30

      Check dir /Users/zhanggangmin/build-opencv-for-android-master/android_opencv/build_service_armeabi-v7a (create: True, clean: True)

      =====

      ===== Building library for armeabi-v7a (arm-linux-androideabi-4.8)

      =====

      Executing: ['cmake', '-GNinja', "-DCMAKE_TOOLCHAIN_FILE='/Users/zhanggangmin/build-opencv-for-android-master/opencv/platforms/android/android.toolchain.cmake'", '-DWITH_OPENCL=OFF', '-DWITH_CUDA=OFF', '-DWITH_IPP=OFF', '-DBUILD_EXAMPLES=OFF', '-DBUILD_TESTS=OFF', '-DBUILD_PERF_TESTS=OFF', '-DBUILD_DOCS=OFF', '-DBUILD_ANDROID_EXAMPLES=ON', '-DINSTALL_ANDROID_EXAMPLES=ON', '-DANDROID_STL=gnustl_static', '-DANDROID_NATIVE_API_LEVEL=9', "-DANDROID_ABI='armeabi-v7a with NEON'", '-DWITH_TBB=ON', '-DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.8', "-DOPENCV_EXTRA_MODULES_PATH='/Users/zhanggangmin/build-opencv-for-android-master/opencv/modules'", '/Users/zhanggangmin/build-opencv-for-android-master/opencv', '-DNDK_CCACHE=ccache', '-DBUILD_TESTS=ON', '-DINSTALL_TESTS=ON']

      CMake Error at platforms/android/android.toolchain.cmake:451 (message):

        Could not find neither Android NDK nor Android standalone toolchain.

       

            You should either set an environment variable:

              export ANDROID_NDK=~/my-android-ndk

            or

              export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain

            or put the toolchain or NDK in the default path:

              sudo ln -s ~/my-android-ndk /opt/android-ndk

              sudo ln -s ~/my-android-toolchain /opt/android-toolchain

      Call Stack (most recent call first):

        /usr/local/share/cmake-3.9/Modules/CMakeDetermineSystem.cmake:94 (include)

        CMakeLists.txt:114 (project)

       

       

      CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage

      CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage

      — Configuring incomplete, errors occurred!

      Traceback (most recent call last):

        File "build_sdk.py", line 305, in <module>

          builder.build_library(abi, do_install)

        File "build_sdk.py", line 148, in build_library

          execute(cmd)

        File "build_sdk.py", line 20, in execute

          raise Fail("Child returned: %s" % retcode)

      __main__.Fail: Child returned: 1

      1. 你好!你是否下载了最新的ndk,并且位置在如信息中所说的/opt/android-ndk目录下?

        另外,extra_modules_path参数要定位到opencv-contrib-android-sdk\sources\opencv_contrib\modules,而不是opencv本身的modules目录

  1. 请问楼主,我想使用aruro, 但是发现使用时 UnsatisfiedLinkError, 请问是不是loadLibrary的问题啊。我该怎么做?

    1. 我已经解决了。是因为我没有安装正确的SDK manger到手机上。

      非常感谢你编译的SDK. 省去了不少时间。

       

      不过aruco还是跑起来报错

    1. 楼主方便给个其他方式吗。人在国外,不知道是不是这个原因。死活下载不下来

  2. 十分感谢楼主的无私分享!这两天也在研究Android下使用SURF和SIFT做图像匹配的应用,正在走投无路准备自己动手编译Android SDK的时候发现了这篇文章,简直太欣慰了。

  3. 第二步修改源码的目的是因为楼主要用到sift和surf,现在我想用contrib里的tracking,是不是就不用修改了?谢谢楼主~

  4. 学长你好,我也是电子科大的,能看到你的博客真的很高兴。我是一名初级android开发人员对jni与opencv不是很懂,最近项目需要在android本地端实现surf,你的取灰度图工程我跑通了,但是contrib加入opencv编译无法通过,不知道学长你能共享一下你编译成功的sdk吗?万分感谢,我的邮箱是:qwer673055793@163.com。

  5. 你好 我想问下 第二步那些代码的修改的目的是什么?  我想用contrib中的bgsegm和xphoto  请问也需要这样修改代码吗?

    1. 你好,你把contrib加入opencv编译通过了吗?我需要用到surf,不知道朋友你能共享下你编译成功的sdk吗?

    2. 层主后来试了么?那些修改的代码怎么回事,不用到特征检测就不用改对吧?只关心contrib里自己需要的东西?

发表评论

电子邮件地址不会被公开。 必填项已用*标注