cmake编译opencv指南

cmake编译opencv指南

用包管理器安装

比如ubuntu下是apt-get,mac下是brew。(windows下或许用nuget?)以ubuntu下为例。

查看opencv相关的包

aptitude search opencv

执行安装

发现有很多包。不妨安装绝大多数:

sudo apt-get install libopencv-*
sudo apt-get install opencv-data python-opencv

编译安装

ubuntu16.04源码编译opencv4.1.0+python3(miniconda/anaconda)

目前(2019年11月18日)我用python都是用miniconda里的python,考虑到python2在2020年会不再维护,直接用python3了。具体版本是python3.7,安装在了/home/zz/soft/miniconda3。
anaconda与miniconda除了预装包不同,其他可以说都一样。

opencv用的4.1.0,目测opencv3.4.x系列也差不多的情况:需要指定"PYTHON3_"开头的各种cmake选项。

cd ~/work
git clone opencv opencv-4.1
cd opencv-4.1
git pull
git checkout -b 4.1.0 4.1.0 #tag 4.1.0
mkdir build
cd build
cmake .. 
    -DCMAKE_INSTALL_PREFIX=/usr/local/opencv-4.1 
    -DINSTALL_PYTHON_EXAMPLES=ON 
    -DOPENCV_PYTHON3_VERSION=3.7 
    -DPYTHON3_EXECUTABLE=/home/zz/soft/miniconda3/bin/python 
    -DPYTHON3_INCLUDE_DIR=/home/zz/soft/miniconda3/include/python3.7m 
    -DPYTHON3_LIBRARY=/home/zz/soft/miniconda3/lib/libpython3.7m.so 
    -DBUILD_opencv_python3=ON 
    -DBUILD_opencv_python2=OFF 
    -DPYTHON_DEFAULT_EXECUTABLE=/home/zz/soft/miniconda3/bin/python 
    -DHAVE_opencv_python3=ON 
    -DBUILD_TIFF=ON

make -j8
sudo make install

(BUILD_TIFF是为了防止编译Caffe时报错提示"对‘TIFFReadDirectory@LIBTIFF_4.0’未定义的引用")

本来以为上面这样之后,就可以用了。C/C++的是可以了,但是python的import cv2会提示:

error: recursion is detected during loading of "cv2" binary extensions

原因是目前的opencv中python加载有bug。参考:https://github.com/opencv/opencv/issues/13202

具体解决办法:

cd ~/work/opencv-4.1/build/python_loader
python setup.py develop

为什么编译安装

opencv有些功能放在opencv_contrib中了,即便用包管理器安装了opencv_contrib,有些包还是不能用,一定要自行把opencvopencv_contrib一起编译。

下载源码

依然以ubuntu16.04为例。

opencv官网下载。或者用git:

mkdir -p ~/gitwhat      #自行建立的目录
cd ~/gitwhat
git clone https://github.com/opencv/opencv --depth=1          #depth表示只下载最新commit的代码,减少下载量。
git clone https://github.com/opencv/opencv_contrib --depth=1
cd opencv
vim compile.sh    #cmake编译参数很多,写到文件中方便些

如果这里要切换版本,那么执行git的切换分支即可。比如指定3.4版:

git branch #查看本地分支,发现之后一个master分支
git branch -r #查看远程分支,发现有个origin/3.4
git checkout -b 3.4 origin/3.4  #切换到远程分支,并且本地分支起名为3.4

对于opencv_contrib也可以这么切换,只不过opencv有2.4版,opencv_contrib没有2.4版

编译脚本

Linux(例如Ubuntu16.04)下,cmake编译脚本compile.sh内容如下

#!/bin/bash
set -x
set -e

rm -rf build
mkdir -p build
cd build

LOG="../cmake.log"
touch $LOG
rm $LOG

exec &> >(tee -a "$LOG")

cmake 
-D CMAKE_BUILD_TYPE=Release 
-D CMAKE_INSTALL_PREFIX=/usr/local/opencv-git-master 
-D WITH_CUDA=OFF 
-D WITH_VTK=OFF 
-D WITH_MATLAB=OFF 
-D BUILD_DOCS=ON 
-D OPENCV_EXTRA_MODULES_PATH=/home/chris/work/gitwhat/opencv_contrib/modules 
-D PYTHON2_EXECUTABLE=/usr/bin/python 
-D PYTHON3_EXECUTABLE=/usr/bin/python3 
-D PYTHON_INCLUDE_DIR=/usr/include/python2.7 
-D PYTHON_INCLUDE_DIR2=/usr/include/x86_64-linux-gnu/python2.7 
-D PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython2.7.so 
-D PYTHON2_NUMPY_INCLUDE_DIRS=/usr/lib/python2.7/dist-packages/numpy/core/include/ 
-D PYTHON3_NUMPY_INCLUDE_DIRS=/usr/lib/python3.5/dist-packages/numpy/core/include/ 
..

make -j8

make doxygen # 可选,用来编译出documentation,存放在`<opencv_root>/build/doc/doxygen/html`

sudo make install #可选,强烈建议执行。

其中,CMAKE_INSTALL_PREFIX表示make install的安装路径,可修改;OPENCV_EXTRA_MODULES_PATHopencv_contrib项目下的modules目录,自行修改。

make install是把opencv和opencv_contrib进行安装到一个统一的目录,如果后续用opencv的C++接口那么当写CMakeLists.txt时需要这个安装路径;如果仅仅是python opencv调用 ,那么只需要找到cv2.so就可以用了,可以不make install

Windows下CMake编译脚本为

cmake ^
-G "NMake Makefiles" ^
-D CMAKE_BUILD_TYPE=Release ^
-D CMAKE_INSTALL_PREFIX=%cd%/install ^
-D WITH_CUDA=OFF ^
-D WITH_VTK=OFF ^
-D WITH_MATLAB=OFF ^
-D BUILD_DOCS=ON ^
-D OPENCV_EXTRA_MODULES_PATH=D:/lib/opencv_contrib/modules ^
-D PYTHON2_EXECUTABLE=D:/soft/Anaconda2/python.exe ^
-D PYTHON_INCLUDE_DIR=D:/soft/Anaconda2/include ^
-D PYTHON_LIBRARY=D:/soft/Anaconda2/libs/python27.lib ^
-D PYTHON2_NUMPY_INCLUDE_DIRS=D:/soft/Anaconda2/Lib/site-packages/numpy/core/include ^
..

其中python使用anaconda安装,并且手动删除Anaconda2Libsite-packages umpy目录,从这里下载64位numpy(例如numpy‑1.15.0+mkl‑cp27‑cp27m‑win_amd64.whl),手动解压并放置到Anaconda2\Libsite-packages目录。

执行编译脚本、解决3rdparty下载

执行编译脚本:

chmod +x compile.sh
./compile.sh

发现往往卡在ippicv等第三方包的下载上(国内网络你懂得)。通过查看相关的.cmake文件,发现是从github上的opencv_3rdparty项目下载的,这些下载地址有些需要改掉,下载第三方包后根据.cmake文件内容,重新压缩、修改md5的hash值等。

这些下载的包放到<opencv_root>/.cache目录下,并按照固定的规则命名。

以下是细节:

设定代理

turn_on_proxy.bat

@echo off 
echo 开始设置IE代理上网 
reg add "HKCUSoftwareMicrosoftWindowsCurrentVersionInternet Settings" /v ProxyEnable /t REG_DWORD /d 1 /f 
reg add "HKCUSoftwareMicrosoftWindowsCurrentVersionInternet Settings" /v ProxyServer /d "http=127.0.0.1:63631;https=127.0.0.1:63631" /f
reg add "HKCUSoftwareMicrosoftWindowsCurrentVersionInternet Settings" /v ProxyOverride /t REG_SZ /d "<-loopback>" /f
echo 代理设置完成按任意键关闭 
pause>nul

turn_off_proxy.bat

@echo off 
echo 开始清除IE代理设置 
reg add "HKCUSoftwareMicrosoftWindowsCurrentVersionInternet Settings" /v ProxyEnable /t REG_DWORD /d 0 /f 
reg add "HKCUSoftwareMicrosoftWindowsCurrentVersionInternet Settings" /v ProxyServer /d "" /f
reg delete "HKCUSoftwareMicrosoftWindowsCurrentVersionInternet Settings" /v ProxyOverride /f
echo IE代理清楚完成按任意键关闭 
pause>nul

如果cmake阶段卡在下载依赖包,并且你本机有代理工具,那么用上面的脚本(注意改下端口)。如果仅仅是开启了lantern的代理和全局代理,cmake下载仍然会失败(我这里是这样的)。

也可以考虑尝试在cmd中设置(我没试过,猜测应该能管用):

::http proxy
set http_proxy=http://127.0.0.1:8118
set https_proxy=http://127.0.0.1:8118

::或者socks proxy
set http_proxy=socks5://127.0.0.1:1080
set https_proxy=socks5://127.0.0.1:1080

手动下载ippicv包

查看<opencv_root>/3rdparty/ippicv/ippicv.cmake
此文件是要下载指定commit的opencv_3rdparty包的URL地址,并给出了验证的md5sum值。

URL地址是有问题的,现在(2017.04.15)不能用raw.githutcontent.com开头形式的URL下载东西了。

换用这个地址:

https://codeload.github.com/opencv/opencv_3rdparty/zip/81a676001ca8075ada498583e4166079e5744668

其中url最后一部分是commit的id

这样下载完的是zip包,解压它并压缩为.tgz格式。算出它的md5sum值。重命名为md5sum-文件名的格式:

1469ff5ced054be500921d2d46278ef4-ippicv_linux_20151201.tgz

移动到<opencv_root>/.cache/ippicv目录下

手动下载protobuf包

查看opencv_contrib/modules/dnn/cmake/OpenCVFindLibProtobuf.cmake
此文件是要下载指定版本的protobuf-cpp。我这里是3.1版本的。它下载地址是:
https://github.com/google/protobuf/releases/download/v3.1.0/
这个地址会转到aws的地址,所以用迅雷下载吧。这个md5sum不用换。

或者下载地址换用这种形式:

https://codeload.github.com/google/protobuf/zip/a428e42072765993ff674fda72863c9f1aa2d268

其中URL最后的commit是protobuf-cpp-3.1对应的commit号。可以试试看。(试了,不行,因该是因为下载的不是protobuf-cpp吧)

xfeatures包

和上面的包的方法类似。只不过放到.cache目录下后,是把一个个的单个文件进行重命名,格式也是md5sum-文件名,记得对比.cmake文件中的hash值。

.cache目录结构

➜  .cache git:(master) ✗ tree
.
├── ippicv
│   └── 1469ff5ced054be500921d2d46278ef4-ippicv_linux_20151201.tgz
├── protobuf
│   └── bd5e3eed635a8d32e2b99658633815ef-protobuf-cpp-3.1.0.tar.gz
├── tiny_dnn
│   └── adb1c512e09ca2c7a6faef36f9c53e59-v1.0.0a3.tar.gz
└── xfeatures2d
    ├── boostdesc
    │   ├── 0ae0675534aa318d9668f2a179c2a052-boostdesc_lbgm.i
    │   ├── 0ea90e7a8f3f7876d450e4149c97c74f-boostdesc_bgm.i
    │   ├── 202e1b3e9fec871b04da31f7f016679f-boostdesc_binboost_064.i
    │   ├── 232c966b13651bd0e46a1497b0852191-boostdesc_bgm_bi.i
    │   ├── 324426a24fa56ad9c5b8e3e0b3e5303e-boostdesc_bgm_hd.i
    │   ├── 98ea99d399965c03d555cef3ea502a0b-boostdesc_binboost_128.i
    │   └── e6dcfa9f647779eb1ce446a8d759b6ea-boostdesc_binboost_256.i
    └── vgg
        ├── 151805e03568c9f490a5e3a872777b75-vgg_generated_120.i
        ├── 7126a5d9a8884ebca5aea5d63d677225-vgg_generated_64.i
        ├── 7cd47228edec52b6d82f46511af325c5-vgg_generated_80.i
        └── e8d0dcd54d1bcfdc29203d011a797179-vgg_generated_48.i

6 directories, 14 files

编译后的设定-环境变量

新编译出来的cv2.so位于/usr/local/opencv-git-master/lib/cv2.so

要使用新编译出来的cv2.so,删除apt的python-opencv包,或者把cv2.so放到PYTHONPATH中。

sudo apt-get remove python-opencv
sudo ln -sf /usr/local/opencv-git-master/lib/python2.7/dist-packages/cv2.so /usr/lib/python2.7

mac下的compile.sh脚本

mac下装caffe时候发现,系统自带的python不靠谱用不了啊,brew的也不怎么能用,所幸有anaconda在。装好anaconda后再brew从源码装boost和boost-python,再caffe。。

对应的opencv编译脚本,改掉python相关的几个路径:

#!/bin/bash
set -x
set -e

LOG="../cmake.log"
touch $LOG
rm $LOG

exec &> >(tee -a "$LOG")

BUILD_ROOT=build

if [ -d $BUILD_ROOT ]; then
    rm -rf $BUILD_ROOT
fi
mkdir -p $BUILD_ROOT
cd $BUILD_ROOT


ANACONDA=/Users/tusdk/anaconda

cmake 
    -D CMAKE_BUILD_TYPE=Release 
    -D CMAKE_INSTALL_PREFIX=/usr/local/opencv-git-master 
    -D WITH_CUDA=OFF 
    -D WITH_VTK=OFF 
    -D WITH_MATLAB=OFF 
    -D BUILD_DOCS=ON 
    -D OPENCV_EXTRA_MODULES_PATH=/Users/tusdk/work/opencv_contrib/modules 
    -D PYTHON2_EXECUTABLE=${ANACONDA}/bin/python 
    -D PYTHON_INCLUDE_DIR=${ANACONDA}/include/python2.7 
    -D PYTHON_LIBRARY=${ANACONDA}/lib/libpython2.7.dylib 
    -D PYTHON2_NUMPY_INCLUDE_DIRS=${ANACONDA}/lib/python2.7/site-packages/numpy/core/include/ 
    ..

make -j8

make doxygen # 可选,用来编译出documentation,存放在`<opencv_root>/build/doc/doxygen/html`

sudo make install

编译OpenCV Android库

  • 官方提供下载的opencv android sdk,依赖过多,模块过多,放手机上app太大了。
  • 首先下载安装ndk,cmake和ninja;
  • 下载opencv源码,这里用opencv-3.4.9和opencv4.2测试OK
  • opencv源码,注意移除modules目录中绝大多数子目录,只保留core, imgcodec, imgproc, highgui, photo等必要模块
  • ndk我用的r18b,(可选) 删除debug编译参数,缩小二进制体积 android-ndk issue (from ncnn的wiki页
# 用编辑器打开 $ANDROID_NDK/build/cmake/android.toolchain.cmake
# 删除 "-g" 这行
list(APPEND ANDROID_COMPILER_FLAGS
  -g
  -DANDROID

For example, windows下编译脚本(arm64-v8a)

@echo off

set BUILD_DIR=arm64-v8a
set ANDROID_NDK=D:/soft/Android/android-ndk-r17c
set ANDROID_SDK=/Users/chris/Library/Android/sdk

if not exist %BUILD_DIR% md %BUILD_DIR%

cd %BUILD_DIR%

cmake -G Ninja ^
    -D CMAKE_TOOLCHAIN_FILE=%ANDROID_NDK%/build/cmake/android.toolchain.cmake ^
    -D CMAKE_BUILD_TYPE=Release ^
    -D CMAKE_INSTALL_PREFIX=%cd%/install ^
    -D WITH_CUDA=OFF ^
    -D WITH_VTK=OFF ^
    -D WITH_MATLAB=OFF ^
    -D WITH_FFMPEG=OFF ^
    -D BUILD_DOCS=OFF ^
    -D WITH_JASPER=OFF ^
    -D WITH_TIFF=OFF ^
    -D WITH_WEBP=OFF ^
    -D WITH_OPENEXR=OFF ^
    -D WITH_IMGCODEC_HDR=OFF ^
    -D WITH_IMGCODEC_SUNRASTER=OFF ^
    -D WITH_IMGCODEC_PXM=OFF ^
    -D WITH_IMGCODEC_PFM=OFF ^
    -D WITH_QUIRC=OFF ^
    -D BUILD_opencv_python3=OFF ^
    -D BUILD_opencv_python2=OFF ^
    -D OPENCV_PYTHON_SKIP_DETECTION=ON ^
    -D WITH_FFMPEG=OFF ^
    -D BUILD_JAVA=OFF ^
    -D WITH_PROTOBUF=OFF ^
    -DBUILD_ANDROID_EXAMPLES=OFF ^
    -DINSTALL_ANDROID_EXAMPLES=OFF ^
    -DANDROID_ABI='arm64-v8a' ^
    -DANDROID_TOOLCHAIN='clang' ^
    -DANDROID_PLATFORM_ID='2' ^
    -DANDROID_NATIVE_API_LEVEL='21' ^
    -DANDROID_STL='c++_static' ^
    ../..

cd ..

注意:

  • 默认会开启WITH_CAROTENE选项,这个是在HAL层做加速用的底层库,例如resize的NEON加速
  • 如果是要编armeabi-v7库,要用ANDROID_ABI='armeabi-v7a with NEON'
  • 官方提供的platforms/android/build_setup.py真的忒难用了

查看OpenCV官方CI配置输出

OpenCV的PullRequests summary页面,查看自己感兴趣的build,点进去,看cmake的输出,即可。

例如android 4.3.0 pre版本的:https://pullrequest.opencv.org/buildbot/builders/precommit_windows64/builds/23961

其他问题

opencv_world.so

编译opencv_contrib时候发现没有编译出opencv_world.so

需要cmake开启开关:

···
-D BUILD_opencv_world=ON
···

缺点:只生成一个opencv_world.so,其他的.so都没有!

编译opencv_contrib时报错Unknown CMake command ‘ocv_download’

问题出现原因:opencv_contrib里面用到的ocv_download函数没有找到对应的定义。很可能是:你的opencv是下载的.zip/.rar压缩包并且版本比较老(比如opencv-2.4.13.zip),而老版本的opencv中没有定义ocv_download函数

因为opencv_contrib模块只提供了opencv3的支持,只能放弃opencv2版本,或者手动去修改各种头文件和函数接口(暂时不考虑

重新编译时,再次需要下载ippicv等模型文件

建议搜索cmake目录下所有文件中的"file(REMOVE",注释掉对应的行。出现本状况的原因是opencv的cmake代码中,执行完下载和解压后就执行删除,好不容易下载好的东西就删除。。不理解这种做法。。

opencv4.1.1 Ubuntu16.04 编译:

cmake .. -DCMAKE_BUILD_TYPE=Release -DOPENCV_GENERATE_PKGCONFIG=ON -DCMAKE_INSTALL_PREFIX=/usr/local/opencv-4.1.1

note: OPENCV_GENERATE_PKGCONFIG用来生成opencv4.pc,给pkg-config用,Makefile中使用。

opencv 3.1.0 windows 3rdparty下载

链接:https://pan.baidu.com/s/1-OHA8bTy3s8E1s482eHpWA
提取码:wpwj

解压后放到3rdparty目录

OpenCV 3.1 VS2017编译后没法被find_pacakge()识别

这是历史包袱,因为OpenCV3.1的cmake install脚本中没有处理VS2017这一runtime。

找到OpenCV3.1源码中cmake目录,修改

  • OpenCVConfig.cmake
  • OpenCVDetectCXXCompiler.cmake

这两个文件,改法一致,都是找到MSVC的判断的最后部分,添加:

  elseif(MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS_EQUAL 1920) #VS2017
    set(OpenCV_RUNTIME vc15)
  elseif(MSVC_VERSION GREATER_EQUAL 1920) #VS2019
    set(OpenCV_RUNTIME vc16)

使用OpenCV Windows预编译包提供的Python接口(cv2)

方式1:临时改sys.path:

import sys
sys.path.insert(1, '/path/to/opencv/build/python/cv2/python-x.y')
import cv2

例如我是:

sys.path.insert(1, 'D:/lib/opencv/4.3.0/build/python/cv2/python-3.7')

注意:用sys.path.insert(1而不是sys.path.insert(0,因为0位置上表示“执行当前脚本的目录”,可能会包含一些和三方依赖库同名的文件,如果改掉了则可能导致冲突。ref

(update:测试发现,还和PATH有关系。。)

方式2:长期使用,则拷贝到Python的site-packages路径下,例如:

D:/lib/opencv/4.3.0/build/python/cv2  => D:/soft/Miniconda3/Lib/site-packages/cv2

D:/lib/opencv/4.3.0/build/python/cv2  => D:/soft/Python37/Lib/site-packages/cv2

其中原生Python是3.7.7测试的,Miniconda的Python是3.7.4测试的,简单的imwrite函数测试通过,其他未验证。

P.S. 现在的Python(python3.6或更高版本,❤️.6的不确定),它自带的pip用来安装numpy,scipy,matplotlib等科学计算的包,已经非常方便了,以往Python2.7自带的pip死活装不上numpy的问题一去不复返了,Anaconda/Miniconda之流存在的意义又少了一层。

指定需要编译的模块(modules)

-DDBUILD_LIST=来设定。例如:

cd opencv
git checkout 3.4
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release
-DCMAKE_INSTALL_PREFIX=/your/path/to/opencv-compile
-DBUILD_LIST=core,imgcodecs,python_bindings_generator,python3,av_stream,dnn_innference
-DOPENCV_EXTRA_MODULES_PATH=/your/path/to/pybindcpp/modules/
-DBUILD_opencv_python3=ON
-DSOFTFP=ON ..

ref: pybindcpp

原文地址:https://www.cnblogs.com/zjutzz/p/6714490.html