linux系统下的OPENCV编译

原链接:http://blog.sina.com.cn/s/blog_602f87700102vdnw.html

1. 下载和准备工作:
编译平台:Fedora17, Fedora20
http://opencv.org/downloads.html
选择了Version 2.4.10   OpenCV for AndroidSource下载。
与OpenCV2.0使用autoconfig不同,OpenCV2.4 已经采用CMake管理Source。

必须预先安装的软件有:
a. jdk
b. Android SDK (revision 14以上)
c. Android NDK
d. Apache Ant. (Version 1.9以上)
e: Python.
请注意版本限制,如果版本过低,编译中会遇到问题。
Sam主编译机器时FC17, yum install ant 会被安装Apache Ant 1.8.就遇到编译问题。后来手动下载 
  • http://ant.apache.org 1.9版本。才解决问题。 但还是做了个软链接 /usr/ant
副编译机采用FC 20 .   yum install ant本身就是Apache Ant1.9. 所以没有问题。
如果运行ant,可能会发现找不到库,
( Error: Couldnot find or load main classorg.apache.tools.ant.launch.Launcher)
则需要
exportCLASSPATH=.:$JAVA_HOME/bin/dt.jar:$JAVA_HOME/lib/tools.jar:/usr/share/java/ant-launcher.jar


2. 设置环境变量:
export ANDROID_NDK=/opt/android-ndk-r9d/
export ANDROID_SDK=/home/sam/android-sdks/
export ANDROID_ABI=armeabi-v7a

export ANT_HOME=/usr/local/apache-ant-1.9.4
export PATH=${PATH}:${ANT_HOME}/bin



3. cmake产生Makefile:
#cd platforms/
#shscripts/cmake_android_arm.sh 

这个shell脚步会创建build_android_arm目录,并将Makefile文件放置在其中。

Sam需要确保Java modules包含在其中。否则不会产生libopencv_java.so

--   OpenCV modules:
--     To be built:              core androidcamera flannimgproc highgui features2d calib3d ml video legacy objdetect photogpu ocl nonfree contrib javastitching superres ts videostab

如果发现Cmake 产生的这个列表中,有些设置需要修改。可以尝试察看:
opencv-2.4.10/CMakeLists.txt, 它同时也include很多.mk文件(opencv-2.4.10/cmake目录内)。 看看具体是什么原因。

例1:刚开始无论如何无法使Java 加入编译模块。
Unavailable:               dynamicudaJava python viz
后来只好跟踪 CMakeLists.txt, 直到OpenCVDetectApacheAnt.cmake中,才发现:
execute_process(COMMAND ${ANT_EXECUTABLE} -version
后出错。 这里ANT_EXECUTABLE就是ant. 
才意识到ant未安装造成问题。

例2:
Sam想把所有Example都编译出来,但 C/C++ Examples:显示NO。
察看CMakeLists.txt, 看到其和BUILD_EXAMPLES 相关, 于是作如下修改:
opencv-2.4.10/platforms/scripts/cmake_android_arm.sh中添加:
-DBUILD_EXAMPLES=1

则C++ Example也被加入编译了。



  4.编译:
#cd opencv-2.4.10/platforms/build_android_arm
#make



5.OpenCV一些附加模块支持: 
OpenCV在不断更新中,添加了很多模块,但这些模块并未添加入代码树中。例如:Eigen,TBB,OpenCL等。需要自己处理。

5.1: 对Eigen的支持
platforms/scripts/cmake_android_arm.sh 中添加:
-DHAVE_EIGEN=1
此时 调用:  shscripts/cmake_android_arm.sh 
关于Eigen的结果有点异常:
--   Other third-party libraries:
--     Use Eigen:               YES (ver ..)
没有得到版本号,则一定没有找到对应头文件等。查看CMakeLists.txt。以下几项内容缺失。
${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION}

跟踪检查:cmake/OpenCVFindLibsPerf.cmake
其中与此相关的是:
if(WITH_EIGEN)
  find_path(EIGEN_INCLUDE_PATH"Eigen/Core"
           PATHS/usr/local /opt /usr  ENV ProgramFiles ENVProgramW6432
          PATH_SUFFIXES include/eigen3 include/eigen2 Eigen/include/eigen3Eigen/include/eigen2
           DOC "Thepath to Eigen3/Eigen2 headers"
          CMAKE_FIND_ROOT_PATH_BOTH)

  if(EIGEN_INCLUDE_PATH)
   ocv_include_directories(${EIGEN_INCLUDE_PATH})
   ocv_parse_header("${EIGEN_INCLUDE_PATH}/Eigen/src/Core/util/Macros.h"EIGEN_VERSION_LINES EIGEN_WORLD_VERSION EIGEN_MAJOR_VERSIO
N EIGEN_MINOR_VERSION)
    set(HAVE_EIGEN 1)
  endif()
endif(WITH_EIGEN)

 find_path()含义是:在PATHS后面的目录内查找Eigen/Core目录。查到了,则目录存放在EIGEN_INCLUDE_PATH中。否则写入NOFound。
然后在Eigen/src/Core/util/Macros.h找到版本号并存储。

所以当前是因为没有Eigen Source Tree造成问题。Sam下载( https://bitbucket.org/erublee/eigen-android/get/2e2c8da72443.zip)并把它放在3rdparty/eigen中。
并修改cmake/OpenCVFindLibsPerf.cmake 相关内容为:

if(WITH_EIGEN)
  find_path(EIGEN_INCLUDE_PATH"Eigen/Core"
           PATHS/usr/local /opt /usr/home/sam/work/current/Research/OpenCV/opencv-2.4.10/3rdparty/eigen ENV ProgramFiles ENV Pro
gramW6432
          PATH_SUFFIXES include/eigen3 include/eigen2 Eigen/include/eigen3Eigen/include/eigen2
           DOC "Thepath to Eigen3/Eigen2 headers"
          CMAKE_FIND_ROOT_PATH_BOTH)
       message(SamInfo)

       message(${EIGEN_INCLUDE_PATH})

  if(EIGEN_INCLUDE_PATH)
   ocv_include_directories(${EIGEN_INCLUDE_PATH})

       message(${EIGEN_INCLUDE_PATH})
   ocv_parse_header("${EIGEN_INCLUDE_PATH}/Eigen/src/Core/util/Macros.h"EIGEN_VERSION_LINES EIGEN_WORLD_VERSION EIGEN_MAJOR_VERSIO
N EIGEN_MINOR_VERSION)
    set(HAVE_EIGEN 1)
  endif()
endif(WITH_EIGEN)

此时调用:  shscripts/cmake_android_arm.sh 
--   Other third-partylibraries:
--     Use Eigen:                YES( ver 2.92.0)

5.2: 关于OpenCL:
因为OpenCL依赖于芯片支持,而Sam发现当前几个芯片(ARM)均不支持OpenCL。所以哪怕将OpenCL编译入OpenCV,其实没有使用到。



5.3: TBB支持:
platforms/scripts/cmake_android_arm.sh 中添加:
-DBUILD_TBB=ON -DWITH_TBB=ON
此时 调用:  shscripts/cmake_android_arm.sh 
则会自动下载TBB for ARM来使用。并编译入OpenCV库。



6. 附加讲解:
编译过程非常明晰简单,即:
sh scripts/cmake_android_arm.sh
此时,可以在cmake_android_arm.sh中添加一些配置如下:
cmake -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DHAVE_EIGEN=1-DWITH_V4L=1 -DHAVE_CAMV4L2=ON -DBUILD_TBB=ON -DWITH_TBB=ON -DBUILD_EXAMPLES=1 -DANDROID_ABI="armeabi-v7a" -DCMAKE_TOOLCHAIN_FILE=../android/android.toolchain.cmake$@ ../..
但这些配置均会起作用么?不一定。

当前我们要编译Android ARM版本,那OpenCVHighGUI中如何使用何种接口控制Camera呢?在Linux时代,有libv4l,V4L2等接口。在Android时代,还可以使用它们么? Sam为了测试这一点,添加了:
-DWITH_V4L=1 -DWITH_LIBV4L=1 -DHAVE_CAMV4L2=ON
下面就看看是否有效.

察看CMakeLists.txt
可以看到以下几类:
A: 
OCV_OPTION(WITH_V4L          "Include Video 4 Linux support"            ON   IF (UNIX AND NOT ANDROID))
OCV_OPTION(WITH_LIBV4L        "Use libv4l for Video 4 Linuxsupport"       ON   IF (UNIX AND NOT ANDROID))
在这里,如果不是Android版本,WITH_V4L,WITH_LIBV4L才会被设置为ON。

B: 
#----------------------------------------------------------------------------
#   Detect 3rd-partylibraries
#----------------------------------------------------------------------------

include(cmake/OpenCVFindLibsGrfmt.cmake)
include(cmake/OpenCVFindLibsGUI.cmake)
include(cmake/OpenCVFindLibsVideo.cmake)
include(cmake/OpenCVFindLibsPerf.cmake)
其中, OpenCVFindLibsVideo.cmake中有相关设置:
ocv_clear_vars(HAVE_LIBV4L HAVE_CAMV4L HAVE_CAMV4L2HAVE_VIDEOIO)
#Sam info:先把HAVE_XXXX信息先clean掉。再根据WITH_XXX设置之。

if(WITH_V4L)
  if(WITH_LIBV4L)
    CHECK_MODULE(libv4l1HAVE_LIBV4L1)
    CHECK_MODULE(libv4l2HAVE_LIBV4L2)
    if(HAVE_LIBV4L1 ANDHAVE_LIBV4L2)
     set(HAVE_LIBV4L YES)
    else()
     set(HAVE_LIBV4L NO)
    endif()
  endif()
  CHECK_INCLUDE_FILE(linux/videodev.hHAVE_CAMV4L)
  CHECK_INCLUDE_FILE(linux/videodev2.hHAVE_CAMV4L2)
  CHECK_INCLUDE_FILE(sys/videoio.hHAVE_VIDEOIO)
endif(WITH_V4L)




所以,在 cmake_android_arm.sh中,
1:修改 HAVE_CAMV4L这样的设置,并无多大用户,因为后面会被 WITH_LIBV4L设置所修改。所以只设置 WITH_XXXX就好。
2. 哪怕设置 WITH_XXXXX。但也会被各种具体细节所修改。例如,是否Android,是否Win等。



7. AndroidNativeC版本编译:
Sam需要编译一个纯NativeC 程序,它使用到OpenCV2.4.10.按照之前的认识,直接编译一个Android版本,使用libopencv_java.so即可。但在实际使用中,发现使用NativeC程序,无法正常访问Camera。后来重新编译OpenCV,并引导它改用V4L2,解决了此问题。现将过程记录如下:
7.1: 问题发现:
运行程序:发现和Camera相关处全都会抱错,提示要求重新编译OpenCV。
Sam从Camera相关第一个function查起:cvCaptureFromCAM()

在modules/highgui/include/opencv2/highgui/highgui_c.h中,有
#define cvCaptureFromCAM cvCreateCameraCapture

在modules/highgui/src/cap.cpp中,
有其实现:CV_IMPL CvCapture * cvCreateCameraCapture (intindex)
它其实就是根据配置来选择调用何种接口,Sam在OpenCV2.0编译时,利用编译选项使它指向libv4l和v4l2俩接口。

7.2: 尝试修改:
既然之前使用libv4l和v4l2接口能够成功。那咱们就继续来。
在platforms/scripts/cmake_android_arm.sh中,增加以下选项
-DWITH_V4L=1 -DWITH_LIBV4L=1 -DHAVE_CAMV4L2=ON

编译后,发现并未被指向libv4l 或者v4l2。找原因:
CMakeLists.txt看到以下语句:
OCV_OPTION(WITH_V4L          "IncludeVideo 4 Linux support"             ON   IF(UNIX AND NOT ANDROID) )
OCV_OPTION(WITH_LIBV4L       "Use libv4l for Video 4 Linux support"      ON   IF (UNIX AND NOT ANDROID))
只有非Android平台时,才会把WITH_V4L和WITH_LIBV4L置ON
 
所以修改之:
#Sam modify it
#OCV_OPTION(WITH_V4L           "Include Video 4 Linuxsupport"              ON   IF (UNIX AND NOT ANDROID))
OCV_OPTION(WITH_V4L           "Include Video 4 Linuxsupport"              ON   IF (UNIX) )
把非Android版本才允许WITH_V4l 的要求去掉。
 

 
cmake/OpenCVFindLibsVideo.cmake中:
ocv_clear_vars(HAVE_LIBV4L HAVE_CAMV4L HAVE_CAMV4L2HAVE_VIDEOIO)
if(WITH_V4L)
  if(WITH_LIBV4L)
    CHECK_MODULE(libv4l1HAVE_LIBV4L1)
    CHECK_MODULE(libv4l2HAVE_LIBV4L2)
    if(HAVE_LIBV4L1 ANDHAVE_LIBV4L2)
     set(HAVE_LIBV4L YES)
    else()
     set(HAVE_LIBV4L NO)
    endif()
  endif()
  CHECK_INCLUDE_FILE(linux/videodev.hHAVE_CAMV4L)
  CHECK_INCLUDE_FILE(linux/videodev2.hHAVE_CAMV4L2)
  CHECK_INCLUDE_FILE(sys/videoio.hHAVE_VIDEOIO)
endif(WITH_V4L)

此处,会查找linux/videodev2.h,来决定HAVE_CAMV4L2为ON。
但不知为何,它总找不到。不知道CHECK_INCLUDE_FILE()找的是哪个目录。
于是强行修改:

# --- V4L ---
status("  WITH_V4L:" ${WITH_V4L})
status("  HAVE_LIBV4L:" ${HAVE_LIBV4L})
status("  HAVE_CAMV4L:" ${HAVE_CAMV4L})
status("  HAVE_CAMV4L2:"${HAVE_CAMV4L2})
status("  HAVE_VIDEOIO:"${HAVE_VIDEOIO})
ocv_clear_vars(HAVE_LIBV4L HAVE_CAMV4L HAVE_CAMV4L2HAVE_VIDEOIO)
if(WITH_V4L)
  if(WITH_LIBV4L)
    CHECK_MODULE(libv4l1HAVE_LIBV4L1)
    CHECK_MODULE(libv4l2HAVE_LIBV4L2)
    if(HAVE_LIBV4L1 ANDHAVE_LIBV4L2)
     set(HAVE_LIBV4L YES)
    else()
     set(HAVE_LIBV4L NO)
    endif()
  endif()
  CHECK_INCLUDE_FILE(linux/videodev.hHAVE_CAMV4L)
  CHECK_INCLUDE_FILE(linux/videodev2.hHAVE_CAMV4L2)
  CHECK_INCLUDE_FILE(sys/videoio.hHAVE_VIDEOIO)

#sam add it
set(HAVE_CAMV4L YES)
set(HAVE_CAMV4L2YES)
status("  HAVE_LIBV4L:" ${HAVE_LIBV4L})
status("  HAVE_CAMV4L:" ${HAVE_CAMV4L})
status("  HAVE_CAMV4L2:"${HAVE_CAMV4L2})
status("  HAVE_VIDEOIO:"${HAVE_VIDEOIO})

endif(WITH_V4L)
此时,V4L2被作为底层编译进去了。

7.3: 察看原来路径:
那之前没加入V4L2 之前呢?看看OpenCV是怎么做的。
因为:HAVE_ANDROID_NATIVE_CAMERA被设置,所以走了:
cvCreateCameraCapture_Android()这路。它最终调用Camera_activity.cpp中的classCameraWrapperConnector去处理Camera。这里需要用到:
libnative_camera_r2.2.0.so
libnative_camera_r2.3.3.so
.....
libnative_camera_r4.4.0.so
但具体选择哪一个,不知道用什么规则来确定。
看起来这条路是通的阿,其实不然,这条路相信是给JNI-C中使用Camera准备的,它密切依赖于OpenCV-Manager.对Native-C程序来说并不适用。如果强行编译使用,会被锁死。
这条路径,Sam称之为:Native-Camera 路径。

7.4:堵住原生Native-Camera路径:
Sam 在cmake/templates/opencvconfig.cmake.in中,删除:
set(OpenCV_HAVE_ANDROID_CAMERA@HAVE_opencv_androidcamera@)

在modules/highgui/CMakeList.txt中,删除:
add_definitions(-DHAVE_ANDROID_NATIVE_CAMERA)
即可堵住Native-Camera。


7.5: 局限:
此方法编译出的库,有非常大的局限性,除非必须使用NativeC方式使用OpenCV,否则不要用此方法,因为它破坏了原生JNI-C方式使用Camera的路径。不建议使用。

 
 
 
8.OpenCV3.1的编译
随着项目的升级,又需要在NativeC下使用OpenCV3.1.  继续采用OpenCVfor Android 为基础编译,修改其Camera路径为V4L2或者libv4l.使之不再依赖于OpenCVManager而独立在NativeC层存在。
 
8.1: 下载OpenCV3.1 Source Code:
需要使用git下载。在 https://github.com/itseez/opencv 页面,得到git地址,
git clone https://github.com/Itseez/opencv.git
 
8.2:确认版本:
modules/core/include/opencv2/core/version.hpp:
#defineCV_VERSION_MAJOR   3
#defineCV_VERSION_MINOR   1
#define CV_VERSION_REVISION 0
 
8.3: 增加对V4L,V4L2等的支持:
A:在platforms/scripts/cmake_android_arm.sh中,增加以下选项
-DWITH_V4L=1 -DWITH_LIBV4L=1 -DHAVE_CAMV4L2=ON
 
B:CMakeLists.txt修改以下语句:
#Sam modify it
#OCV_OPTION(WITH_V4L           "Include Video 4 Linuxsupport"              ON   IF (UNIX AND NOT ANDROID))
OCV_OPTION(WITH_V4L           "Include Video 4 Linuxsupport"              ON   IF (UNIX) )
把非Android版本才允许WITH_V4l 的要求去掉。
 
C:cmake/OpenCVFindLibsVideo.cmake中
if(WITH_V4L)
  if(WITH_LIBV4L)
    CHECK_MODULE(libv4l1HAVE_LIBV4L1)
    CHECK_MODULE(libv4l2HAVE_LIBV4L2)
    if(HAVE_LIBV4L1 ANDHAVE_LIBV4L2)
     set(HAVE_LIBV4L YES)
    else()
     set(HAVE_LIBV4L NO)
    endif()
  endif()
  CHECK_INCLUDE_FILE(linux/videodev.hHAVE_CAMV4L)
  CHECK_INCLUDE_FILE(linux/videodev2.hHAVE_CAMV4L2)
  CHECK_INCLUDE_FILE(sys/videoio.hHAVE_VIDEOIO)

#sam add it
set(HAVE_CAMV4L YES)
set(HAVE_CAMV4L2YES)
status("  HAVE_LIBV4L:" ${HAVE_LIBV4L})
status("  HAVE_CAMV4L:" ${HAVE_CAMV4L})
status("  HAVE_CAMV4L2:"${HAVE_CAMV4L2})
status("  HAVE_VIDEOIO:"${HAVE_VIDEOIO})

endif(WITH_V4L)
 
8.4:处理编译问题:
根据以上设置,会在调用时cvCreateCameraCapture()调用cvCreateCameraCapture_V4L().
且modules/videoio/cap_v4l.cpp会被编译进来。
但NDK中的v4l2的头文件比较老,会导致一些错误(未定义错误)
Sam直接在cap_v4l.cpp中添加如下语句解决之:
//sam add it
#define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G', 'B','R', 'G')
#defineV4L2_CTRL_CLASS_CAMERA           0x009a0000
#defineV4L2_CID_CAMERA_CLASS_BASE       (V4L2_CTRL_CLASS_CAMERA | 0x900)
#defineV4L2_CID_FOCUS_ABSOLUTE                  (V4L2_CID_CAMERA_CLASS_BASE+10)
#defineV4L2_CID_FOCUS_AUTO                      (V4L2_CID_CAMERA_CLASS_BASE+12)
 
 8.5:处理FFMPEG库添加问题:
Sam并不是用正规做法加入FFMPEG支持,所以,在OpenCV编译时,常会发现找不到ffmpeg 符号的问题:
 
例如:
Linking CXX executable../../bin/opencv_perf_videoio
../../lib/armeabi-v7a/libopencv_videoio.a(cap_ffmpeg.cpp.o):cap_ffmpeg.cpp:functionInternalFFMpegRegister::~InternalFFMpegRegister(): error: undefinedreference to 'av_lockmgr_register'
 
Sam的解决方法是:
在类似以下文件:
modules/videoio/CMakeFiles/opencv_perf_videoio.dir/link.txt
加入以下语句:
-lffmpeg -L../../3rdparty/ffmpeg/android/armv7-a/
这个方法并不正规。但先这么处理了。(Sam把单独编译的ffmpeg放在了platforms/build_android_arm/3rdparty/ffmpeg/android)
 

 

附录:
错误记录:
[ 73%] Building OpenCV Android library project
/usr/bin/ant -q -noinput -k debug
   [subant] No sub-builds toiterate on
Target '-compile' failed with message 'The following erroroccurred while executing this line:
/home/sam/android-sdks/tools/ant/build.xml:734: Class notfound: javac1.8'.
Cannot execute '-dex' - '-compile' failed or was notexecuted.
Cannot execute '-package' - '-dex' failed or was notexecuted.
Cannot execute '-do-debug' - '-package' failed or was notexecuted.
Cannot execute 'debug' - '-do-debug' failed or was notexecuted.

BUILD FAILED
/home/sam/android-sdks/tools/ant/build.xml:720: The followingerror occurred while executing this line:
/home/sam/android-sdks/tools/ant/build.xml:734: Class notfound: javac1.8

Total time: 3 seconds
make[2]: *** [bin/classes.jar] Error 1
make[2]: Leaving directory`/home/sam/work/current/Research/OpenCV/opencv-2.4.10/platforms/build_android_arm'
make[1]: *** [modules/java/CMakeFiles/opencv_java.dir/all]Error 2
make[1]: Leaving directory`/home/sam/work/current/Research/OpenCV/opencv-2.4.10/platforms/build_android_arm'
make: *** [all] Error 2
[sam@KingOfLinux build_android_arm]$ ant -version
Apache Ant(TM) version 1.8.3 compiled on February 292012
[sam@KingOfLinux build_android_arm]$ javac -version
javac 1.8.0_20

这个错误是因为ANT 版本太低造成的。
Sam升级到1.9版本即可。

你可能感兴趣的:(安卓系统开发)