作者: Sam (甄峰)
sam_code@hotmail.com
自从2011年开始交叉编译OpenCV, 到今天陆陆续续编译了很多版本,
有尝试过编译Linux版本(http://blog.sina.com.cn/s/blog_602f87700102wuv7.html),交叉编译过ARM版本,在Android版本出现后,又编译过OpenCV4Android
(http://blog.sina.com.cn/s/blog_602f87700102wwvb.html)
(http://blog.sina.com.cn/s/blog_602f87700102xdzq.html).
编译这么多次后,希望对自己的编译历程做个总结,所以借这次机会记录下来。
0. 交叉编译OpenCV的原因:
0.1:OpenCV2.0时代:
最初交叉编译OpenCV,是想在Android系统上使用它,而在OpenCV2.0时代,并不提供Android版本。所以下载了OpenCV2.0
Source For Linux. 对各个模块自己写Android.mk, Application.mk.
顺利的编译出对应版本。
cvaux,cv, cxcore,
ml, highgui等全部成功编译。且highgui底层支持V4L2, libv4l, ffmpeg等
(http://blog.sina.com.cn/s/blog_602f87700101de4o.html)
0.2: OpenCV3.1时代:
OpenCV3.1时代,已经开始提供OpenCV4Android,理论上,根本不需要再自行编译.
OpenCV的官方建议是: 直接使用OpenCV库。libopencv_java.so.
并提供了两套使用方法:
A. 利用OpenCV提供的全套Java接口, 在Android Java层使用。
B. 利用OpenCV提供的C/C++ 接口, 在JNI层使用。
但Sam当时需要比较特殊: 与官方提供过使用方法不同的是:需要在Android
NativeC控制台层面使用OpenCV。这本身没有问题,但会遇到Camera问题(注1)。
换句话说,就是要在Android NativeC 层, 把V4L2支持也打开。这就是每升级一次OpenCV,
Sam都需要重新编译的核心原因。
0.3: OpenCV3.4时代:
从OpenCV3.3. 它加入了DNN,需要用它,还想把OpenCL加入。又需要用到Camera,所以.....
1. OpenCV编译思路:
既然知道了特殊的OpenCV使用要求(在NativeC控制台程序中使用OpenCV, 同时提供Camera接口)。
那编译思路就很清晰了。
1.1:打开所有想要支持的模块和功能:
如:TBB, Eigen, OpenCL.
1.2: 打开V4L2支持。
此处要注意,使用官方方法打开V4L2支持,并不一定可以起效。因为在设置文件中,这个设置会被去掉。
1.3:堵住Native-JNI所用的Camera接口:
这个接口是给JNI-NativeC用的,与OpenCV-Manager关联。不是Sam所能使用的。所以需要把这条路堵住。
2. 编译方法研究总结:
回顾:
OpenCV2.0时代,当时编译工具还采用autoconf. 所以直接自己写Android.mk ,
Application.mk。
OpenCV2.4.20时代,编译工具切换到cmake. 所以编译方法有所变化。直到OpenCV3.4,
(OpenCV4.0还没看)。 一直可以延续这种编译方法。(中间也许添加了Python编译方法,后续再研究)。
首先看这种编译方法:
2.1: 几个关键文件:
A. CMakeLists.txt
在OpenCV Source Tree根目录。有CMakeLists.txt. 它是OpenCV CMake 的根
Makefile。
B: platforms/scripts 目录:
V2.4.20, V3.1.0
V3.3.0中,platforms/scripts目录中,有很多 sh 脚本。
这些脚本用来帮助开发人员编译不同平台,不同架构的OpenCV.
cmake_android_arm.sh :
Android ARM平台版本。
cmake_android_mips.sh: Android MIPS平台版本
cmake_android_x86.sh: X86版本。
cmake_arm_gnueabi_hardfp.sh: ARM
hardfp版本。
其中,我们用到的就是cmake_android_arm.sh 。
这些脚本,其实是帮助开发人员编译的。
它的主要思想是:
#cd platforms
#sh
scripts/cmake_android_arm.sh
它就会在platforms下建立一个类似
build_android_arm的目录。并生成(新产生,而非copy)将要编译的源码和头文件以及Makefile。等待用户编译。
其中,不同平台,不同架构的的编译设置,
-DCMAKE_TOOLCHAIN_FILE=../android/android.toolchain.cmake:放在platforms/中不同目录内。
如:android, ios, linux,
osx等。
android-ARM的编译配置文件:就在android/android.toolchain.cmake 中 .
C: platforms/android
这个目录放置的是android-arm版本的编译设置选项。
其中,V3.4.1版本,在platforms/scripts中,已经没有cmake_android_arm.sh
了。
但在platforms/android/ 增加了build_sdk.py , ndk-xx.config.py等。
估计是为python编译准备的。
不过,既然platforms/android/android.toolchain.cmake
还在,那老版本应该还行的通。
3. 编译前的准备工作:
不同OpenCV版本的编译中,要求各个软件和库的版本也在不断升级中。所以就不提具体版本了。只说需要什么软件吧。
git
cmake
Android NDK
JDK
Android SDK
Apache Ant
Python.
环境变量设置:
export ANDROID_NDK=/opt/android-ndk-r14b/
export ANDROID_SDK=/home/sam/Android/android-sdk-linux/
#export ANDROID_SDK=/home/sam/Android/Sdk/
export ANDROID_ABI=armeabi-v7a
export ANT_HOME=/usr/share/ant
export PATH=${PATH}:${ANT_HOME}/bin
Sam 把他们写到一个脚本中:
SET_ENV_32BIT
#source
SET_ENV_32BIT
4.
实际编译:
4.1:设置环境变量:
#source
SET_ENV_32BIT
4.2:
哪怕是V3.4.1, Sam也建议自己建立scripts/cmake_android_arm.sh.
这样在后续修改设置,如加入TBB,OpenCL等时,就直接添加在cmake_android_arm.sh 中了。
#cd platforms
#sh scripts/cmake_android_arm.sh
#cd build_android_arm
#make VERBOSE=1
5.
修改OpenCV设置:
5.1: Eigen支持添加:
A. 添加设置:
在scripts/cmake_android_arm.sh 中,添加:
-DHAVE_EIGEN=1
但此时可以看到:
-- Other third-party
libraries:
--
Eigen:
YES (ver
..)
说明没找到Eigen的库和头文件。
查看CMakeLists.txt, 可以看到以下语句:
if(WITH_EIGEN OR HAVE_EIGEN)
status("
Eigen:"
HAVE_EIGEN
THEN "YES (ver
${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION})"
ELSE NO)
endif()
说明没有获取到以上信息。
查看CMakeList.txt:
OCV_OPTION(WITH_EIGEN
"Include
Eigen2/Eigen3 support"
(NOT
CV_DISABLE_OPTIMIZATION)
IF (NOT WINRT AND NOT
CMAKE_CROSSCOMPILING) )
可以看到,如果是交叉编译,则WITH_EIGEN不被设置。
所以如果需要加入EIGEN支持,首先要交叉编译EIGEN, 再去掉这个语句。这个后面再尝试。
5.2: 添加TBB支持:
添加设置:
-DWITH_TBB=1
它会自动下载TBB。
5.3: 增加动态库:
-DBUILD_SHARED_LIBS=ON
5.4:增加V4L2支持:
注1:
OpenCV中本机Camera支持:
Android Camera的原生接口与平台相关。
OpenCV将依赖于平台的代码隔离到单独的库中,并提供了几个预构建的库。如:
libnative_camera_r2.2.0.so
libnative_camera_r4.0.3.so
libnative_camera_r4.1.1.so等。
OpenCV的本机Camera在控制台应用程序中不起作用。
注2:
WITH_EIGEN, HAVE_EIGNE, WITH_TBB, HAVE_TBB关系。