暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Ubuntu下安装OpenCV(二): CMake编译(上)

麟十一 2021-11-03
2460

 第 26 篇  |  LINSHIYI 



这是Ubuntu下安装OpenCV系列的第二篇:CMake编译(上)。本文以OpenCV3.4.10Ubuntu18.04为例,使用Debug模式对OpenCV核心算法和额外算法进行CMake编译,并生成适用于Unix/Linux系统的Makefile等编译文件。


CMake编译这一步共有2篇文,分为3个部分。第一部分介绍CMake命令行中的各个参数;第二部分分析某些文件/压缩包下载失败的原因,并给出多种解决方法;第三部分展示编译结果


这是CMake编译的上篇,包含第一部分和第二部分(1)-(2)小节的内容,以概念解释为主,下篇会以实践为主,包括第二部分的(3)-(4)小节和第三部分。


目录--2.CMake编译


上图是这个系列的目录索引,之前的文章都在这里:

 OpenCV配置攻略(一):OpenCV, VC++和VS
 OpenCV配置攻略(二): 安装包里都有什么(上) 本文主要介绍CMake编译这一步,推荐提前阅读2.4节(3)-(4)中介绍CMake和make的部分
 OpenCV配置攻略(二): 安装包里都有什么(下) 本文涉及一小部分库文件的内容,推荐提前阅读3.3节(3)-(6)中有关库文件的部分
 Ubuntu下安装OpenCV(一): 准备工作 

CMake编译



第四步:CMake编译,生成适用于Ubuntu系统的Makefile及相关文件
命令执行位置:构建目录下
命令行:
$ sudo cmake -D CMAKE_BUILD_TYPE=<compile mode> \
-D CMAKE_INSTALL_PREFIX=<install_directory> \
-D OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules \
<opencv_source_directory>
注意:
1. CMAKE_BUILD_TYPE的参数大小写敏感,如 Debug/Release/RelWithDebInfo/MinSizeRel 等 
2. 自行选择库文件的安装路径<install_directory>,默认为/usr/local
3. <opencv_contrib>指额外算法文件夹的路径
4. <opencv_source_directory>指核心算法文件夹的路径
5. 自行增加或减少cmake命令后的变量
6. ippicv压缩包、vgg_*.i系列文件、boostdesc_*.i系列文件和face_landmark_model.dat数据集可能会下载失败

复制


首先说明,CMake编译这一步需要在构建文件夹下执行,直接在源代码文件夹下执行命令会报错:

直接在源代码文件夹下进行CMake编译

下面是我输入的命令语句,用户需要根据自己的文件路径做调整

先使用命令cd debug/进入第3步创建好的构建目录下,之后输入sudo cmake -D CMAKE_BUILD_TYPE=Debug -D CMAKE_INSTALL_PREFIX=/usr/local/opencv-3-4-10-debug -D OPENCV_EXTRA_MODULES_PATH=/home/用户名/downloads/opencv_contrib-3.4.10/modules ..执行编译任务。(排版有些乱

CMake编译

这一步一般不会报错,如果出现错误,先考虑是否输错了命令,比如参数拼写错误、路径中漏写分隔符"/"、忘记写最后的两个点、在两个点之前没有敲空格等等,再检查路径中是否有中文,以及opencv_contrib和opencv的版本是否一致。如果以上问题都没有出现,再根据具体报错信息检查错误原因。

4.1 命令行介绍


(1) cmake -D


观察上文输入的命令,可以发现命令行的格式为sudo cmake -D <变量>=<值> ..,cmake是CMake的命令语句,-D是cmake命令中的一个选项,它用于创建或更新CMake的缓存


在编译过程中,CMake会自动缓存目的配置信息,比如编译模式、OpenCV版本号、文件的存放路径等。有了这些缓存,CMake在同一目录下再次执行编译任务时,就无需重新编译整个项目,只编译与当前缓存不同的内容即可。

所有的CMake缓存项都会被保存在一个叫CMakeCache.txt的文件中。这个文件会在CMake开始编译时自动生成,位于构建目录下(https://cmake.org/runningcmake/)

The cache is best thought of as a configuration file. The first time CMake is run, it produces a CMakeCache.txt file. This file contains things like the existence and location of native JPEG library.


简单看一下CMake运行完毕后CMakeCache.txt的内容,所有配置都会以<variable>:<type>=<value>的格式被存储:

CMakeCache.txt

上图中变量OPENCV_EXTRA_MODULES_PATH负责设置OpenCV额外算法模块的路径,该变量默认为空值,由于我们在命令行中使用-D为变量设置了新的值,所以CMake的缓存也被更改。这个变量在第(4)小节会有详细介绍。


命令行中为变量赋值


每当我们对项目有了新的配置,都需要使用-D <variable>=<value>来更新CMake缓存。另外,-D和变量名之间的空格可以去掉,比如-D CMAKE_BUILD_TYPE=Debug也可以写成-DCMAKE_BUILD_TYPE=Debug。


更多有关-D和其他选项(如-C、-S等)的介绍可以在官方文档中查找到(https://cmake.org/cmake/help/v3.21/manual/cmake.1.html)

 
(2) CMAKE_BUILD_TYPE

 

CMAKE_BUILD_TYPE变量


我们在上一篇中介绍过编译模式的概念,项目的编译模式就是通过参数CMAKE_BUILD_TYPE进行设置的(https://cmake.org/cmake/help/v3.21/variable/CMAKE_BUILD_TYPE.html)

 

This statically specifies what build type (configuration) will be built in this build tree. Possible values are empty, Debug, Release, RelWithDebInfo, MinSizeRel, ... This variable is only meaningful to single-configuration generators (such as Makefile Generators and Ninja).

 

从定义中可以看到,这个变量只对单一配置生成器(Single-Configuration Generators)有效,单一配置生成器一次只能生成包含一种编译模式的配置文件,常见的有Makefile生成器和Ninja生成器(https://cmake.org/cmake/help/v3.21/guide/tutorial/Packaging%20Debug%20and%20Release.html)

 

By default, CMake's model is that a build directory only contains a single configuration, be it Debug, Release, MinSizeRel, or RelWithDebInfo.

 

我们在Ubuntu系统上使用的是Makefile生成器,也就是说,CMake编译时生成的Makefile等构建文件,只能包含Debug、Release、MinSizeRel、RelWithDebInfo等编译模式中的一种。如果既想要Debug模式的构建文件,又想要Release模式的构建文件,就需要使用CMake编译两次每次为CMAKE_BUILD_TYPE设置不同的参数

 

除了单一配置生成器(Single-Configuration Generators),还有一种生成器叫多元配置生成器(Multi-Configuration Generators),即一次可以生成多种编译模式的项目文件的生成器。


对于多元配置生成器来说,变量CMAKE_BUILD_TYPE是无效的,需要使用另一个变量CMAKE_CONFIGURATION_TYPES来设置(https://cmake.org/cmake/help/latest/variable/CMAKE_CONFIGURATION_TYPES.html)


Specifies the available build types on multi-config generators. This specifies what build types (configurations) will be available such as Debug, Release, RelWithDebInfo etc.


下图是我在Windows下使用Visual Studio生成器进行CMake编译的过程截图,Visual Studio生成器属于多元配置生成器,从图中可以看出变量CMAKE_CONFIGURATION_TYPES默认写入了Debug和Release两种编译模式,我们可以在“Value”中在追加其他的编译模式,并以分号分隔:


CMAKE_CONFIGURATION_TYPES变量


为了方便理解这一部分的内容,我画了一张示意图,上面部分是我们目前在Ubuntu系统下使用Makefile生成器(单一配置生成器)进行编译和生成库文件的过程,下面部分是在Windows下使用Visual Studio生成器(多元配置生成器)进行编译和生成文件的过程:


单一/多元配置生成器示意图


另外,还有一点需要注意,无论是参数CMAKE_BUILD_TYPE还是CMAKE_CONFIGURATION_TYPES,它们的值都是大小写敏感的,例如正确的参数是Debug/Release,写成debug/release是无效的。


(3) CMAKE_INSTALL_PREFIX
 

CMAKE_INSTALL_PREFIX变量


参数CMAKE_INSTALL_PREFIX用来设置OpenCV编译生成的头文件、库文件、可执行程序等文件的存放路径。Unix/Linux系统默认将这些文件保存在/usr/local/下的bin、lib、include和share四个目录下(https://cmake.org/cmake/help/v3.21/variable/CMAKE_INSTALL_PREFIX.html)


This variable defaults to /usr/local on UNIX and C:/Program Files/${PROJECT_NAME} on Windows.

 

使用默认的安装路径会有一个问题,不同版本、不同编译模式的头文件、库文件多有重名,如果将这些文件都安装在同一目录下,重名文件会相互覆盖,导致链接库文件失败、程序无法成功运行等问题。

 

所以,如果我们想安装多个版本的OpenCV,或者生成多个编译模式的库文件,不建议使用默认的安装路径,应该为每个版本、每种编译模式生成的文件,设置单独的存放目录

 

我将OpenCV3.4.10(debug版)生成的文件存放在了/usr/local/opencv-3-4-10-debug/下,其它版本的文件路径也都遵循/usr/local/opencv-<version>-<mode>的格式,如/usr/local/opencv-3-4-10-release,/usr/local/opencv-4-5-3-release等,用户可以根据自己的喜好来设置文件夹名称,只要起到区分版本/编译模式的作用即可

 

更多有关变量CMAKE_INSTALL_PREFIX的解释见https://cmake.org/cmake/help/v3.21/variable/CMAKE_INSTALL_PREFIX.html


(4)OPENCV_EXTRA_MODULES_PATH


OPENCV_EXTRA_MODULES_PATH变量


OPENCV_EXTRA_MODULES_PATH是配置opencv_contrib中的额外算法模块所必须的参数,如果我们不使用额外算法,这个参数就无需设置

(https://docs.opencv.org/master/db/d05/tutorial_config_reference.html)

 

OPENCV_EXTRA_MODULES_PATH option contains a semicolon-separated list of directories containing extra modules which will be added to the build.

 

定义中的a semicolon-separated list of directories(以分号分割的目录列表)需要做一下解释。如果我们想要使用所有的额外模块,就可以设置OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules,因为modules文件夹下包含了所有算法的源代码文件


opencv_contrib中的modules文件夹


但如果我们只需要其中的一个模块,例如face模块,那么参数就可以设置为OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules/face

 

如果想编译两个或多个模块,就需要用分号将不同模块的路径分隔开,例如我们想要编译faceplot模块,参数就是OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules/face\; <opencv_contrib>/modules/plot。分号前的"\"是转义符,不可以省略。(另外,这里的命令应该是一行,因为排版问题可能看上去像是两行

 

(5) <opencv_source_directory>


<opencv_source_directory>


这是cmake命令中需要设置的最后一个变量,位置在命令行的结尾,不可以调整变量顺序。<opencv_source_directory>指的是OpenCV核心算法源代码目录下CMakeLists.txt所在的路径

 

cmake命令会执行名为CMakeLists.txt文件中的语句,所以需要保证程序在<opencv_source_directory>路径下可以顺利寻找到CMakeLists.txt文件:

 

CMakeLists.txt和构建目录的位置

 

如上图所示,我们进行CMake编译时所在的目录是构建目录debug,也就是核心算法文件夹下的子目录,而CMakeLists.txt位于根目录下,换句话说,CMakeLists.txt位于构建目录debug的父目录下

 

在Unix/Linux系统中,父目录可以用两个英文句号来表示,当前目录可以用一个英文句号来表示(https://discourse.ubuntu.com/t/the-linux-command-line-for-beginners)

 

In the same way that two dots (..) represents the parent directory, so a single dot (.) can be used to represent the current working directory.

 

所以对于<opencv_source_directory>参数来说,用户可以直接输入两个点,而无需输入完整的OpenCV源代码文件夹路径。

 

(6)其他参数

 

除去上文提到的参数,用户在编译时还可以自己添加相关的参数,比如设置BUILD_EXAMPLES=ON来生成所有样例,设置BUILD_JAVA=OFF不生成OpenCV的Java支持文件,设置BUILD_opencv_<modules_name>=OFF不编译指定的模块等等。


在构建目录下输入cmake-L可以输出项目可用的所有变量和默认参数,输入cmake -LH还可以输出变量注释

 

项目可用的CMake变量及其说明


这里的CMake报错可以忽略掉,因为我们并不是要运行CMakeLists.txt中的命令,只是查看可用的参数而已。我们也可以通过查看官方文档来寻找有用的变量(https://cmake.org/cmake/help/v3.21/manual/cmake-variables.7.html)


4.2 有关下载失败的问题


在CMake编译这一步中,除去报错,大概率还会遇到文件/压缩包下载失败的问题,这主要是由于网速不佳或者连接不上GitHub造成的文件下载超时错误。一般会有4种文件/压缩包下载失败:ippicv压缩包、vgg_*.i系列文件、boostdesc_*.i系列文件和face_landmark_model.dat数据集。


CMake下载失败警告--ippicv压缩包


这一节分为4个部分,第一部分会对这4种可能下载失败的文件/压缩包做简要介绍,第二部分通过下载日志来解析CMake的下载逻辑,第三部分给出手动下载文件的两种方法,第四部分会详细介绍3种解决办法。本文包括前两部分,下一篇包括后两部分。


(1)包的简介


先来说说ippicv压缩包,对于OpenCV3.0以及更高的版本,英特尔集成性能原语库(Integrated Performance Primitives, IPP)提供了一个名为IPPICV的子集,它可以作为第三方库链接在OpenCV中,提升程序的运行速度

 

如果我们不想使用这个优化器的话,可以在cmake命令中加入-D WITH_IPP=OFF语句来关闭IPPICV加速,这样在CMake编译的过程中就不会自动下载IPPICV压缩包,我们也就不会遇到下载ippicv失败的问题了。

 

更多有关优化器的内容见https://github.com/opencv/opencv/wiki/CPU-optimizations-build-options
 

更多有关IPPICV的内容见Intel官网https://software.intel.com/content/www/us/en/develop/articles/intel-integrated-performance-primitives-intel-ipp-open-source-computer-vision-library-opencv-faq.html

 

vgg_*.i系列文件、boostdesc_*.i系列文件和face_landmark_model.dat数据集都是额外算法模块用到的文件。


vgg_*.i和boostdesc_*.i属于额外的二维特征算法模块(Extra 2D Features Framework,简称xfeatures2d),face_landmark_model.dat属于人脸识别模块(Face Recognition,简称face)

 
Features2D extra -- Extra 2D Features Framework containing experimental and non-free 2D feature detector/descriptor algorithms. SURF, BRIEF, Censure, Freak, LUCID, Daisy, Self-similar.

 

xfeatures2d包括了实验性的特征提取算法(Experimental 2D feature algorithms)和一些受到专利保护的算法(Non-free 2D feature algorithms)。CMake默认不编译受专利保护的算法,用户需要使用-D OPENCV_ENABLE_NONFREE=ON来生成该算法所需的文件(上文定义来自https://github.com/opencv/opencv_contrib/tree/master/modules)

 

face_landmark_model.dat是人脸识别模块中有关人脸特征探测(Face Landmark Detection)的训练集(https://github.com/opencv/opencv_3rdparty/tree/contrib_face_alignment_20170818)

 

This contains binary file contaning the trained model for one millisecond face landmark detection.

 

使用语句-D BUILD_opencv_<extra modules name>=OFF可以不编译某个额外模块,例如对于刚刚的xfeatures2d和face模块,用户可以使用-D BUILD_opencv_xfeatures2d=OFF和-D BUILD_opencv_face=OFF语句来跳过编译,当然,跳过编译之后用户也就无法使用这些算法了。

 

一些教程中,针对vgg_*.i和boostdesc_*.i系列文件下载失败的问题所给出的解决方案就是在cmake语句中加入-D BUILD_opencv_xfeatures2d=OFF,这对于不打算使用xfeatures2d模块的用户来说是一个方法,但是对于需要使用此模块的用户来说,这种方法并不能解决问题。


(2)CMake的下载逻辑

 

接下来分析一下CMake在执行下载任务时遵循的逻辑,本小节会涉及两个文件,一个是构建目录下的下载日志;一个是负责OpenCV下载和解压缩任务的文件OpenCVDownload.cmake,它位于源代码目录中的cmake文件夹下。


下载日志名为CMakeDownloadLog.txt,它记录了CMake在执行下载任务时所经历的所有步骤,CMake每编译一次,日志就会被重写一次。通过查看日志中的内容,我们可以了解每个文件的具体下载/解压缩信息


CMakeDownloadLog.txt


OpenCVDownload.cmake定义了OpenCV下载文件/压缩包的函数ocv_download()、还负责输出下载日志。通过解读这个文件,我们可以了解CMake在下载文件/压缩包时执行的任务逻辑


OpenCVDownload.cmake


我将OpenCVDownload.cmake中的主要逻辑画成了一张图(省略部分细节内容),方便理解CMake下载文件时需要执行的步骤
 
CMake的下载任务包括压缩包任务文件任务两种,下图绿色部分是下载文件时执行的逻辑线,红色部分是下载压缩包时执行的逻辑线,紫色部分为二者共用的逻辑

#号的内容是输出到下载日志中的语句,图中被水印挡住的文字是“新建目录并解压缩”。


CMake下载逻辑


紫色逻辑共有2个部分,上面的部分是初始任务:判断下载目录是否存在->判断CMake是否成功执行过此任务->初始化下载日志->判断任务模式。下面的部分包括了文件/压缩包的下载和签名校验任务

 

文件任务的主逻辑是:检查目标目录下是否存在该文件->检查下载目录下是否存在该文件->下载文件->复制文件至目标目录下。

 

压缩包任务的主逻辑是:检查下载目录下是否存在该文件->下载文件->检查目标目录下是否存在该文件->目标目录下解压缩。

 

这里的下载目录指的是CMake在编译过程中新建的一个名为.cache/的文件夹,用来存放所有的下载文件,该文件夹位于源代码文件夹下。目标目录指的是文件/压缩包下载成功之后被复制/解压缩的文件夹

 

最后详细介绍一下文件/压缩包下载失败时CMake的逻辑线走向:


CMake下载失败时的逻辑


我们需要对照下载日志CMakeDownloadLog.txt来看一看CMake具体执行了哪些操作,下文以ippicv压缩包vgg_generated_64.i文件为例。

 

日志中第一行#use_cache "${OPENCV_DOWNLOAD_PATH}"程序初始化下载日志时输出的内容。OPENCV_DOWNLOAD_PATH是下载目录的路径。从下图可以看到在我的计算机中OpenCV3.4.10的下载目录为/home/用户名/downloads/opencv-3.4.10/.cache。


ippicv压缩包下载失败日志


下载ippicv压缩包时,程序执行压缩包任务(#do_unpack)-->在下载目录.cache/下查找压缩包是否已存在-->未找到-->下载压缩包(#cmake_download,#try)-->下载失败(编译信息输出Download failed)


ippicv压缩包下载失败警告


下图是文件vgg_generated_64.i的下载日志:程序执行文件任务(#do_copy)-->先在目标目录下寻找-->未发现文件(#missing)-->之后在下载目录下寻找-->未找到文件-->下载文件(#cmake_download,#try)-->下载失败(编译信息输出Download failed)


vgg_generated_64.i下载失败日志


vgg_generated_64.i下载失败警告


最后的最后,解释一下刚刚出现的3种语句#do_unpack/copy#missing#cmake_download,并搭配下载日志进行展示,


1. 执行压缩包/文件任务时输出的语句
#do_${mode} "${DL_FILENAME}" "${DL_HASH}" "${DL_URL}" "${DL_DESTINATION_DIR}"
参数:
(1)${mode}  有unpack和copy两种,下载压缩包是unpack模式,下载文件是copy模式
(2)${DL_FILENAME}  文件名称
(3)${DL_HASH}  MD5校验值,可以将它理解为文件的一种数字签名,只有数字签名正确的文件才会被下载
(4)${DL_URL}  文件下载地址,一般是以https开头的一串网址
(5)${DL_DESTINATION_DIR}  目标目录,即文件最终存放的位置/压缩包最终被解压的位置

复制

下面分别标注出了下载日志中ippicvvgg_generated_64.i的#do_${mode}语句:


ippicv压缩包 #do_unpack

vgg_generated_64.i #do_copy

2. 执行文件任务,在目标目录下未找到文件时输出的语句
#missing "${COPY_DESTINATION}"
参数:
(1)${COPY_DESTINATION}  目标目录下文件的路径

复制


由于这条语句只会在CMake执行文件任务时输出,所以下面只展示vgg_generated_64.i的#missing语句:


vgg_generated_64.i #missing


3. 下载文件/压缩包时输出的语句
#cmake_download "${CACHE_CANDIDATE}" "${DL_URL}"
#try
参数:
(1)${CACHE_CANDIDATE}  缓存路径,即存放在.cache/下的文件路径
(2)${DL_URL}  下载地址,这里的下载地址与#do_${mode}中的下载地址相同

复制


下面两张图标注了下载日志中ippicvvgg_generated_64.i的#cmake_download和#try语句:


ippicv压缩包 #cmake_download


vgg_generated_64.i #cmake_download




个人感觉CMake编译是整个安装和配置OpenCV过程中最麻烦的一步 除去输入的命令行比较长之外,这一步可选择的变量也非常多,而且如果用户在这一步忽略掉vgg_*.i和boostdesc_*.i系列文件下载失败的问题,在下一步make编译时,就会遇到因找不到这些文件而出现的报错

下一篇是CMake编译(下) 包括第二部分(3)-(4)小节和第三部分。第(3)小节会给出2种手动下载文件/压缩包的方法,第(4)小节会在CMake下载逻辑的基础上,给出3种解决下载失败问题的办法。第三部分主要是展示CMake编译这一步的输出结果。

这一篇感觉排版好乱,但是我已经尽力了 希望下一篇能好点


~END~


文章转载自麟十一,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论