zoukankan      html  css  js  c++  java
  • 转载---- 使用opencv源码自己编制android so库的过程

    http://blog.csdn.net/lantishua/article/details/21182965

    工作需要,在Android上使用OpenCV。opencv当前的版本(2.4.8)已经有了opencv4android,但是一方面这个SDK将所有opencv的功能打到了一个so包里,所以so的体积较大,从而造成使用该so的apk也大,上层对此不太满意;另一方面,使用opencv4android必须在手机上安装openv manager,上层对此也感觉有点别扭。所以我尝试用opencv的源码自己编译应用于android平台的opencv动态库以供底层开发用。首先介绍一下相关环境:

    opencv:  opencv2.4.8 (Linux)

    系统:ubuntu12.04

    开发环境:eclipse juno(with CDT等),  android ndk r9c

    针对android开发可用的so库需要用ndk build编译,我详细查看了下opencv.org上的文档,上面只有opencv在linux,win等上的编译方法,当然还有opencv4android的使用方法。网上的文档找到一个使用老版本opencv来自己编译的帖子,但版本较老就没采用,所以只能自己分析下opencv的源码写mk文件进行编译。

    为了压缩动态库的体积,也根据自己的实际需求,暂时只编译了三个库:core,imgproc,highgui. 幸运的是,新版本的opencv模块化比较好,所以不存在太多源码拆分的问题。所以,将源码中module文件夹下的三个模块源码放到jni/opencv目录下就可以了。之后在opencv文件夹下编写Android.mk文件,如下:

    LOCAL_PATH:= $(call my-dir)
    ZLIB_PATH:= /home/yxh/eclipse/android-ndk-r9c/platforms/android-14/arch-arm/usr

    #opencv_core module
    include $(CLEAR_VARS)

    LOCAL_MODULE := libopencv_core

    LOCAL_C_INCLUDES :=
            $(LOCAL_PATH)/core/include
            $(ZLIB_PATH)/include
                                   
    LOCAL_CPPFLAGS := -frtti -fexceptions
    LOCAL_LDLIBS += -llog -lz

    LOCAL_SRC_FILES :=
             core/src/precomp.cpp
             core/src/algorithm.cpp
             core/src/alloc.cpp
             core/src/arithm.cpp
             core/src/array.cpp
             core/src/cmdparser.cpp
             core/src/convert.cpp
             core/src/copy.cpp
             core/src/datastructs.cpp
             core/src/drawing.cpp
             core/src/dxt.cpp
             core/src/gpumat.cpp
             core/src/lapack.cpp
             core/src/mathfuncs.cpp
             core/src/matmul.cpp
             core/src/matop.cpp
             core/src/matrix.cpp
             core/src/opengl_interop_deprecated.cpp
             core/src/opengl_interop.cpp
             core/src/persistence.cpp
             core/src/parallel.cpp
             core/src/rand.cpp
             core/src/stat.cpp
             core/src/system.cpp
             core/src/tables.cpp
                            
    include $(BUILD_SHARED_LIBRARY)


    #opencv_imgproc module
    include $(CLEAR_VARS)

    LOCAL_MODULE := libopencv_imgproc

    LOCAL_C_INCLUDES :=
            $(LOCAL_PATH)/core/include
            $(LOCAL_PATH)/imgproc/include
            $(ZLIB_PATH)/include

    LOCAL_CPPFLAGS := -frtti -fexceptions
    LOCAL_LDLIBS += -llog -lz
    LOCAL_SHARED_LIBRARIES := libopencv_core

    LOCAL_SRC_FILES :=
            imgproc/src/accum.cpp
            imgproc/src/approx.cpp
            imgproc/src/canny.cpp
            imgproc/src/clahe.cpp
            imgproc/src/color.cpp
            imgproc/src/contours.cpp
            imgproc/src/convhull.cpp
            imgproc/src/corner.cpp
            imgproc/src/cornersubpix.cpp
            imgproc/src/deriv.cpp
            imgproc/src/distransform.cpp
            imgproc/src/emd.cpp
            imgproc/src/featureselect.cpp
            imgproc/src/filter.cpp
            imgproc/src/floodfill.cpp
            imgproc/src/gabor.cpp
            imgproc/src/generalized_hough.cpp
            imgproc/src/geometry.cpp
            imgproc/src/grabcut.cpp
            imgproc/src/histogram.cpp
            imgproc/src/hough.cpp
            imgproc/src/imgwarp.cpp
            imgproc/src/linefit.cpp
            imgproc/src/matchcontours.cpp
            imgproc/src/moments.cpp
            imgproc/src/morph.cpp
            imgproc/src/phasecorr.cpp
            imgproc/src/pyramids.cpp
            imgproc/src/rotcalipers.cpp
            imgproc/src/samplers.cpp
            imgproc/src/segmentation.cpp
            imgproc/src/shapedescr.cpp
            imgproc/src/smooth.cpp
            imgproc/src/subdivision2d.cpp
            imgproc/src/sumpixels.cpp
            imgproc/src/tables.cpp
            imgproc/src/templmatch.cpp
            imgproc/src/thresh.cpp
            imgproc/src/undistort.cpp
            imgproc/src/utils.cpp    

    include $(BUILD_SHARED_LIBRARY)


    #opencv_highgui module
    include $(CLEAR_VARS)

    LOCAL_MODULE := libopencv_highgui

    LOCAL_C_INCLUDES :=
            $(LOCAL_PATH)/core/include
            $(LOCAL_PATH)/imgproc/include
            $(LOCAL_PATH)/highgui/include
            $(ZLIB_PATH)/include
            /usr/include
            /usr/include/x86_64-linux-gnu

            
    LOCAL_CPPFLAGS := -frtti -fexceptions
    LOCAL_LDLIBS := -llog -lz
    LOCAL_SHARED_LIBRARIES := libopencv_core
    LOCAL_SHARED_LIBRARIES += libjpeg libpng

    LOCAL_SRC_FILES :=
            highgui/src/bitstrm.cpp
            highgui/src/cap.cpp
            highgui/src/cap_ffmpeg.cpp
            highgui/src/cap_images.cpp
            highgui/src/cap_v4l.cpp
            highgui/src/grfmt_base.cpp
            highgui/src/grfmt_bmp.cpp
            highgui/src/grfmt_imageio.cpp
            highgui/src/grfmt_jpeg.cpp
            highgui/src/grfmt_png.cpp
            highgui/src/grfmt_pxm.cpp
            highgui/src/grfmt_sunras.cpp
            highgui/src/loadsave.cpp
            highgui/src/utils.cpp
            highgui/src/window.cpp
            highgui/src/window_gtk.cpp
            highgui/src/grfmt_exr.cpp
            highgui/src/grfmt_tiff.cpp 

    include $(BUILD_SHARED_LIBRARY)

    说几点mk文件中需要注意的地方。

    1、opencv依赖于zlib库,该库在NDK中已经提供了,但要在include的时候加入进去,所以定义了ZLIB_PATH变量,将其指向zlib.h的位置,并在之后三个模块的编译中加入到include中。

    2、LOCAL_CPPFLAGS := -frtti -fexceptions,是编译opencv必须的编译标志,不加会提示exception等错误。如果是在工作中某个系统里(类ANDROID)中增加opencv的功能,但系统的编译选项中没开-frtti,则会在链接的时候报错。

    3、前两个模块比较好弄,因为相对独立,需要注意的是core/include下需要将源码中生成的cvconfig.h文件拷贝过去,这个文件包含很多宏定义来控制opencv编译中哪些功能打开哪些功能关闭。实际上,比较麻烦的是highgui库的编译,以为设计的依赖比较多。首先声明的是,因为功能划分,本人在编译中没有打开gtk+等界面工具,只进行数据的处理。同时,经过查询比较,本人认为现版本Opencv在NDK-BUILD下编译时也不支持ffmpeg的相关功能。我曾经尝试打开ffmpeg相关开关并进行编译调试,调试到后来在源文件中发现某线程功能的条件编译不支持android ndk下的编译(供出源码,摘自cap_ffmpeg_impl.hpp)

    #if defined WIN32 || defined _WIN32 || defined WINCE

    struct ImplMutex::Impl
    {
        void init()
        {
    #if (_WIN32_WINNT >= 0x0600)
            ::InitializeCriticalSectionEx(&cs, 1000, 0);
    #else
            ::InitializeCriticalSection(&cs);
    #endif
            refcount = 1;
        }
        void destroy() { DeleteCriticalSection(&cs); }

        void lock() { EnterCriticalSection(&cs); }
        bool trylock() { return TryEnterCriticalSection(&cs) != 0; }
        void unlock() { LeaveCriticalSection(&cs); }

        CRITICAL_SECTION cs;
        int refcount;
    };

    #ifndef __GNUC__
    static int _interlockedExchangeAdd(int* addr, int delta)
    {
    #if defined _MSC_VER && _MSC_VER >= 1500
        return (int)_InterlockedExchangeAdd((long volatile*)addr, delta);
    #else
        return (int)InterlockedExchangeAdd((long volatile*)addr, delta);
    #endif
    }
    #endif // __GNUC__

    #elif defined __APPLE__

    #include <libkern/OSAtomic.h>

    struct ImplMutex::Impl
    {
        void init() { sl = OS_SPINLOCK_INIT; refcount = 1; }
        void destroy() { }

        void lock() { OSSpinLockLock(&sl); }
        bool trylock() { return OSSpinLockTry(&sl); }
        void unlock() { OSSpinLockUnlock(&sl); }

        OSSpinLock sl;
        int refcount;
    };

    #elif defined __linux__ && !defined ANDROID

    struct ImplMutex::Impl
    {
        void init() { pthread_spin_init(&sl, 0); refcount = 1; }
        void destroy() { pthread_spin_destroy(&sl); }

        void lock() { pthread_spin_lock(&sl); }
        bool trylock() { return pthread_spin_trylock(&sl) == 0; }
        void unlock() { pthread_spin_unlock(&sl); }

        pthread_spinlock_t sl;
        int refcount;
    };

    #else
    struct ImplMutex::Impl
    {
        void init() { pthread_mutex_init(&sl, 0); refcount = 1; }
        void destroy() { pthread_mutex_destroy(&sl); }

        void lock() { pthread_mutex_lock(&sl); }
        bool trylock() { return pthread_mutex_trylock(&sl) == 0; }
        void unlock() { pthread_mutex_unlock(&sl); }

        pthread_mutex_t sl;
        int refcount;
    };
    #endif

    上述条件编译最后在NDK下走到了#else,而pthread_mutex_init出自wp32threads.h,该头文件中第一依赖于windows.h。。。android下玩不转了。。。

    另外,分析了下opencv4android的config发现也没打开ffmpeg,同时从论坛里看到某外说道现版本opencv在android上确不支持ffmpeg。所以本人认为现版本opencv从源码上对android下的ffmpeg调用就不支持,这一点如果各位有别的见解,欢迎讨论。

    接上文,所以本人在编译highgui模块时也关闭了ffmpeg相关的依赖,但为了能够支持图片的存取操作,打开了jpeg,png的依赖,所以在mk文件中有

    LOCAL_C_INCLUDES :=

    /usr/include
    /usr/include/x86_64-linux-gnu

    LOCAL_SHARED_LIBRARIES += libjpeg libpng

    这两个库的编译也是从相关官网上下载源码,编写mk文件,这两个库的mk文件是从网上找来的,粘到jpeg和png源码目录下,ndk-build异常顺利   :-). 下面也贴上两个mk的代码(转载):

    jpeg下Android.mk:

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE := libjpeg

    LOCAL_SRC_FILES :=
            jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c
            jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c
            jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c
            jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c
            jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c
            jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c
            jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c
            jquant2.c jutils.c jmemmgr.c jmemnobs.c


    include $(BUILD_SHARED_LIBRARY)

    png下Android.mk:

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE := libpng
    LOCAL_SRC_FILES := png.c pngerror.c pngget.c pngmem.c pngpread.c pngread.c pngrio.c
                       pngrtran.c pngrutil.c pngset.c pngtrans.c pngwio.c pngwrite.c pngwtran.c
                       pngwutil.c
    LOCAL_LDLIBS := -lz


    include $(BUILD_SHARED_LIBRARY)

    PS:难怪异常顺利,真真没啥依赖。。。

    这样,opencv编译中mk上就没啥可啰嗦的了。但opencv有另外一些重要的依赖本人是在eclipse中设置的,主要是标准C++的支持。在这里提醒大家,编译opencv中一定要使用标准C++,这个在NDK中有带的,具体在sources/cxx-stl/gnu-libstdc++下。如果使用stlport等其他一些C++库,会出现一些问题。本人最初就是使用的stlport,出现了一些问题,为了fix自己改stlport改来改去头大了很麻烦。

    下面给出eclipse中的相关设置:(C/C++ general下paths and symbols中添加)

    ${NDKROOT}/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.6/include

    ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/include

    ${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include

    ${NDKROOT}/platforms/android-9/arch-arm/usr/include

    /home/yxh/OpenCV-2.4.8-android-sdk/sdk/native/jni/include

    /usr/include

    ${JAVA_HOME}/include

    ${NDKROOT}/platforms/android-12/arch-arm/usr/include/

    PS:有些可以去掉,NDK几个应该是必须的,请自行根据实际情况实验。

    设置完以上的东西,最后给出jni下Application.mk:

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

    上面APP_ABI应该设置成相应处理器的,好像有个$ABI的东西可以自适应

    这样,在eclipse下ndk-build就可以生成libopencv_core,libopencv_imgproc,libopencv_highgui三个so库了。这样就可以在自己jni开发中使用Opencv了~

  • 相关阅读:
    [算法导论]红黑树实现(插入和删除) @ Python
    [算法导论]二叉查找树的实现 @ Python
    [leetcode] Min Stack @ Python
    [leetcode]Find Minimum in Rotated Sorted Array II @ Python
    [leetcode]Find Minimum in Rotated Sorted Array @ Python
    [leetcode]Maximum Product Subarray @ Python
    业余办一个【编程语言+数据结构+算法】培训班怎么样?
    [算法导论]merge sort @ Python
    聚合页是什么?网站聚合页如何做?网站聚合页SEO完全实践指南
    SEO实验:相关性的搜索结果静态页面是否也会在百度劲风算法的处理之中?
  • 原文地址:https://www.cnblogs.com/leoking01/p/6625348.html
Copyright © 2011-2022 走看看