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了~

转载---- 使用opencv源码自己编制android so库的过程的更多相关文章

  1. sobel算子原理及opencv源码实现

    sobel算子原理及opencv源码实现 简要描述 sobel算子主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测. 原理 算子使用两个33的矩阵(图1)算子使用两个33的矩阵(图1)去 ...

  2. [转载]JMeter源码导入Eclipse

    转载自:http://www.cnblogs.com/taoSir/p/5144274.html 由于JMeter纯Java开发,界面也是基于Swing或AWT搞出来的,所以想更深层次的去了解这款工具 ...

  3. 【原创】源码角度分析Android的消息机制系列(六)——Handler的工作原理

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 先看Handler的定义: /** * A Handler allows you to send and process {@link Mes ...

  4. OpenCV源码解析

    OpenCV K-means源码解析 OpenCV 图片读取源码解析 OpenCV 视频播放源码解析 OpenCV 追踪算法源码解析 OpenCV SIFT算法源码解析 OpenCV 滤波源码分析:b ...

  5. CMake生成OpenCV解决方案&&编译OpenCV源码

    生成OpenCV工程需要用到CMake,所以第一步需要下载CMake软件,下载链接:CMake下载 目前最新的版本是3.7.1,这里选择下载Platform下的Windows win32-x86 ZI ...

  6. opencv::源码编译

    环境:win10.vs2017.cmake .java.python3.7默认安装. opencv源码:opencv-.zip opencv拓展库源码:opencv_contrib-.zip (注意: ...

  7. 开源项目Telegram源码 Telegram for Android Source

    背景介绍 Telegram 是一款跨平台的即时通信软件,它的客户端是自由及开放源代码软件.用户可以相互交换加密与自毁消息,发送照片.影片等所有类型文件.官方提供手机版.桌面版和网页版等多种平台客户端. ...

  8. Visual Studio调试到OpenCV源码中

    TL;DR VS2015下,build-farm/vs2015-x64/bin/Debug/目录,*.pdb文件,都拷贝到install/x64/vc14/bin目录,就可以调试进去opencv源码了 ...

  9. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

随机推荐

  1. BZOJ 4818 [Sdoi2017]序列计数 ——矩阵乘法

    发现转移矩阵是一个循环矩阵. 然后循环矩阵乘以循环矩阵还是循环矩阵. 据说还有FFT并且更优的做法. 之后再看吧 #include <map> #include <cmath> ...

  2. [SDOI2011] 消防 (树的直径,尺取法)

    题目链接 Solution 同 \(NOIP2007\) 树网的核 . 令 \(dist_u\) 为以 \(u\) 为根节点的子树中与 \(u\) 的最大距离. \(~~~~dis_u\) 为 \(u ...

  3. 【bzoj1191】[HNOI2006]超级英雄Hero - 二分图匹配

    现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的多少获得不同数目的奖品或奖金.主持人问题准备了若干道题目,只有当选手正确回答一道题后,才能进入下一 ...

  4. 微信小程序红包开发思路 微信红包小程序开发思路讲解

    之前公司开发小程序红包,将自己在开发的过程中遇到的一些坑分享到了博客里.不少人看了以后,还是不明白怎么开发.也加了我微信咨询.所以今天,我就特意再写一篇文章,这次就不谈我开发中遇到的坑了.就主要给大家 ...

  5. 乘法逆元__C++

    在开始之前我们先介绍3个定理: 1.乘法逆元(在维基百科中也叫倒数,当然是 mod p后的,其实就是倒数不是吗?): 如果ax≡1 (mod p),且gcd(a,p)=1(a与p互质),则称a关于模p ...

  6. 【MFC】 点击不同的按钮后在界面同一位置显示不同的对话框内容(转)

    原文转自 http://bbs.csdn.net/topics/391039432 如图类似Tab控件的功能    但Tab控件按钮是固定的上下左右  不方便     所以想自己重新做个这种   我M ...

  7. phpcms V9 安装黄页模块后,注册为普通会员并登录,点立即免费入驻企业库出现白板

    解决步骤: 1. 将php.ini修改: display_errors = On 2. 再次尝试,显示出错误: Fatal error: require(): Failed opening requi ...

  8. AC日记——Milking Grid poj 2185

    Milking Grid Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 8314   Accepted: 3586 Desc ...

  9. (3)一般处理程序 ,HttpContext类

    一般处理程序的后缀名 .ashx  ,专门用来处理web请求 新建后默认代码: public class Handler1 : IHttpHandler { public void ProcessRe ...

  10. 基于sklearn的分类器实战

    已迁移到我新博客,阅读体验更佳基于sklearn的分类器实战 完整代码实现见github:click me 一.实验说明 1.1 任务描述 1.2 数据说明 一共有十个数据集,数据集中的数据属性有全部 ...