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. 刷题总结——Human Gene Functions(hdu1080)

    题目: Problem Description It is well known that a human gene can be considered as a sequence, consisti ...

  2. [CQOI2010] 扑克牌 (二分答案,巧解)

    Description 你有n种牌,第i种牌的数目为ci.另外有一种特殊的牌:joker,它的数目是m.你可以用每种牌各一张来组成一套牌,也可以用一张joker和除了某一种牌以外的其他牌各一张组成1套 ...

  3. jacoco功能测试覆盖率统计

    1.在java程序的启动脚本(或者tomcat)中加入javaagent参数-javaagent:/home/apps/jacocoagent.jar=destfile=/home/apps/jaco ...

  4. Docker部署注册中心、Docker创建私有镜像库、自签名证书、Deploy a registry server

    这是我在内部部署Docker Registry时记录下来的笔记,操作环境是Centos 7.Docker 18.06.1-ce 1.运行registry 我当前所使用的主机的IP是192.168.1. ...

  5. 洛谷P1469找筷子

    题目描述 经过一段时间的紧张筹备,电脑小组的“RP餐厅”终于开业了,这天,经理LXC接到了一个定餐大单,可把大家乐坏了!员工们齐心协力按要求准备好了套餐正准备派送时,突然碰到一个棘手的问题,筷子!CX ...

  6. 【BZOJ3524】Couriers(主席树)

    题意:给一个长度为n的序列a.1≤a[i]≤n.m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2.如果存在,输出这个数,否则输出0. n,m≤5000 ...

  7. udp 多播

    先来了解下UDP UDP 是UserDatagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一 ...

  8. guake使用

    1. 安装:sudo apt-get install guake 2. 在终端输入guake 3. f12:显示/隐藏 4. f11:全屏/正常屏切换 5. f2:重命名终端名 6. 还可以查看修改快 ...

  9. 【原】手写spring async异步组件

     最近在工作中使用到了spring自带的Async,主要是为了把其中耗时多.响应慢.计算复杂的业务抽取几个模块出来,并行查询.不得不说spring自带的比传统线程池提交在代码层次上看起来优雅简洁了不少 ...

  10. Css实现一个菜单导航

    提要:使用大div定位设置为relative,子div设置为absolute实现菜单下拉 实现代码: <!DOCTYPE html> <html lang="en" ...