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

Ubuntu下安装OpenCV(五): 配置和测试

麟十一 2021-11-19
2298

 第 26 篇  |  LINSHIYI 



这是Ubuntu下安装OpenCV系列的第五篇:配置和测试。全文共4个部分,对应OpenCV安装步骤的第7步到第10步

第一部分(第7步)将OpenCV的共享库路径添加进系统共享库缓存中;第二部分(第8步)通过正确放置.pc文件,使pkg-config命令可以获取OpenCV生成的头文件、库文件等信息 ;第三部分(第9步)使用updatedb命令更新系统的文件名数据库;第四部分(第10步)使用OpenCV自带的样例进行C++程序测试

本文以OpenCV3.4.10+contrib为例,在Ubuntu18.04下使用Debug模式进行源代码编译,所述方法同样适用于Ubuntu16.04系统。


目录--4. 配置和测试

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

 OpenCV配置攻略(一):OpenCV, VC++和VS
 OpenCV配置攻略(二): 安装包里都有什么(上) 
 OpenCV配置攻略(二): 安装包里都有什么(下) 本文涉及共享库的配置,推荐阅读3.3节(3)-(6)中有关库文件的部分
 Ubuntu下安装OpenCV(一): 准备工作 
 Ubuntu下安装OpenCV(二): CMake编译(上) 

 Ubuntu下安装OpenCV(三): CMake编译(下)

 Ubuntu下安装OpenCV(四): make编译


设置共享库所在路径



第七步: 将OpenCV共享库 (格式为lib*.so.*) 的路径添加进系统共享库缓存中
命令执行位置: /etc/ld.so.conf.d/下
命令行:
$ sudo touch <file name>.conf 创建文件
$ sudo gedit <file name>.conf 编辑文件, 并写入共享库所在位置<install_directory>/lib
$ sudo ldconfig 更新系统共享库缓存
注意:
1. <install_directory>是CMake编译时通过变量CMAKE_INSTALL_PREFIX设置的安装路径, 默认为/usr/local
2. ldconfig 的搜索目录
复制


7.1 ldconfig

 

先来介绍 ldconfig命令的含义和作用 (http://manpages.ubuntu.com/manpages/bionic/en/man8/ldconfig.8.html)

 

ldconfig creates the necessary links and cache to the most recent shared libraries found in the directories specified on the command line, in the file /etc/ld.so.conf, and in the trusted directories, /lib and /usr/lib.

(on some 64-bit architectures such as x86-64, /lib and /usr/lib are the trusted directories for 32-bit libraries, while /lib64 and /usr/lib64 are used for 64-bit libraries).


共享库(Shared Library)也被称为动态库(Dynamic Library)或动态链接库,它会在可执行程序运行时被调用,在Windows系统下格式为*.dll,在Unix/Linux系统下格式为lib*.so.*,例如libopencv_plot.so,libopencv_photo.so.3.4.10等。


ldconfig是一个管理系统共享库的命令,它通过为共享库建立必要的链接和缓存,让计算机中的可执行程序可以成功调用这些库。


计算机中的共享库缓存文件为/etc/ld.so.cache,它存储了系统中所有的共享库名称及路径,这是一个二进制文件,没有办法直接读取,我们可以输入命令ldconfig -p来查看该文件的内容:


ldconfig -p 查看系统中所有的共享库


7.2 ldconfig的搜索目录


从7.1的定义可知,当我们运行可执行程序时,ldconfig命令会从一系列目录中搜索程序所需的共享库,如果找到了库,则程序可以成功调用该库,如果未找到,则程序报错。ldconfig的搜索目录包括系统信任的目录/lib和/usr/lib、还有/etc/ld.so.conf文件中的条目


下面查看一下搜索目录中的内容,先看受信任的目录/lib和/usr/lib


/lib和/usr/lib下的共享库

/usr/lib下保存着许多格式为lib*.so.*的共享库文件,如libgdal.so.20、libgjs.so.0等。/lib下虽然没有共享库,但是ld-linux.so.2是Linux的动态加载器(Dynamic Loader),它用于定位应用程序所需的动态库(共享库),并将其加载到内存中。


接下来看一看/etc/ld.so.conf的内容,该文件并没有记录共享库的具体路径。在我的计算机中,它只有一条语句include /etc/ld.so.conf.d/*.conf,其中include表示载入并运行文件内容,*.conf代表所有后缀为.conf的文件。所以这条语句的含义是读取/etc/ld.so.conf.d/目录下所有后缀为.conf的文件


/etc/ld.so.conf


进入/etc/ld.so.conf.d/目录下,可以看到许多后缀为.conf的文件,使用cat命令查看其中两个文件libc.conf和x86_64-linux-gnu.conf的内容,发现.conf文件中记录的才是具体的共享库路径


/etc/ld.so.conf.d 目录下的内容


总结来说,ldconfig的搜索顺序是:检查/lib和/usr/lib目录-->读取/etc/ld.so.conf文件的内容-->根据include语句进入/etc/ld.so.conf.d 目录下挨个读取.conf文-->前往.conf文件记录的路径下查找共享库


7.3 操作步骤

 

(1) 新建.conf文件并写入共享库路径


第一步,我在/etc/ld.so.conf.d 文件夹下新建了一个名为opencv-3-4-10d.conf的文件,并写入debug版共享库的路径/usr/local/opencv-3-4-10-debug/lib。文件名没有特殊要求,但是一定要加.conf后缀,共享库的路径需要用户根据自己的系统来修改。


sudo touch <file name>命令可以新建指定名称的文件,sudo gedit <file name>命令可以编辑文件。


新建.conf 文件并写入共享库路径

(2) 更新系统共享库路径缓存


保存好.conf文件之后可以使用cat命令查看一下路径的拼写是否正确,之后输入sudo ldconfig命令更新系统共享库的路径缓存即可


sudo config命令

在一些教程中提到,用户可以将共享库的路径写入/etc/ld.so.conf文件中,这样ldconfig在读取该文件时 ,就可以直接进入路径下查找共享库。这种方法是可以的,不过我个人更喜欢单独创建一个文件来存放路径,感觉文件结构会更清晰一些。


设置头文件和共享库选项


第八步: 让pkg-config命令可以正确输出OpenCV算法头文件和共享库的信息
命令执行位置: pkg-config命令的搜索路径下, 下文使用的是/usr/lib/pkgconfig 目录
命令行:
$ sudo cp <install_directory>/lib/pkgconfig/opencv.pc /usr/lib/pkgconfig/<file name>.pc
注意:
1. <install_directory>是CMake编译时通过变量CMAKE_INSTALL_PREFIX设置的安装路径, 默认为/usr/local
2. pkg-config 的搜索路径
3. .pc文件的作用和内容
4. 检验pkg-config的设置是否生效

复制

8.1 pkg-config


还是先来介绍一下pkg-config命令,这个命令用于获取某个已安装的库的编译信息(https://www.freedesktop.org/wiki/Software/pkg-config/)


pkg-config is a helper tool used when compiling applications and libraries. It helps you insert the correct compiler options on the command line so an application can use gcc -o test test.c `pkg-config --libs --cflags glib-2.0` for instance, rather than hard-coding values on where to find glib (or other libraries).

 

当我们在使用g++命令执行编译任务时,编译用到的头文件和库文件路径都需要写入命令行中,如果链接的库太多,命令行就会变得很长。pkg-config可以帮助我们使用简单的语句输出一系列头文件和库文件的路径信息

 

pkg-config命令后可以添加很多选项,命令行中输入pkg-config -h可以查看所有可用的选项。常用的选项有--cflags--libs--modversion。 --cflags会输出预处理器和编译器选项(也就是头文件的名称和路径),--libs会输出链接器选项(即库文件的名称和路径),--modversion可以输出版本号


pkg-config -h命令

8.2 .pc文件


那么pkg-config是如何获取已安装库的信息呢?答案是从后缀为.pc的文件中读取(定义来自$man pkg-config)

 

pkg-config retrieves information about packages from special metadata files. These files are named after the package, and has a .pc extension.

 

.pc文件记录了库的各种信息,包括库的版本、编译模式、头文件路径、库文件路径等。这个文件一般是由第三方库提供的,用户也可以自己来编写。


OpenCV作为第三方库,就为我们提供了.pc文件,在2.x和3.x版本中名为opencv.pc,在4.x版本中名为opencv4.pc


在之前编译的过程中,.pc文件一共生成了两次。第一次生成是在make编译这一步:


make编译时生成opencv.pc

该文件被保存在构建目录下的unix-install文件夹中:


unix-install下的opencv.pc

第二次生成是在make install这一步:


make install时生成的opencv.pc文件 

.pc文件被安装在<install_directory>/lib/pkgconfig下,这里的<install directory>是我们在CMake编译时通过变量CMAKE_INSTALL_PREFIX设置的安装路径:

<install directory>/lib/pkgconfig下的opencv.pc

两个.pc文件是相同,使用cat命令来查看一下具体的文件内容:

 

opencv.pc中的内容

文件注释为"Package Information for pkg-config",文件中记录了OpenCV的简介、版本号、库文件路径、头文件路径等内容。pkg-config命令中的选项--cflags、--libs和--modversion就是在读取该文件中Cflags、Libs和Version中的内容。

8.3 pkg-config的搜索路径


仅仅生成了.pc文件还是不够的,想要pkg-config成功输出.pc文件的内容,就需要将该文件放置在pkg-config的搜索路径下(定义来自$man pkg-config)

 

On most systems, pkg-config looks in /usr/lib/pkgconfig, /usr/share/pkgconfig, /usr/local/lib/pkgconfig and /usr/local/share/pkgconfig for these files. 

It will additionally  look in the colon-separated (on Windows, semicolon-separated) list of directories specified by the PKG_CONFIG_PATH environment variable.

 

定义中只列举了一部分pkg-config的搜索路径,在命令行输入pkg-config --variable pc_path pkg-config可以查看自己系统中pkg-config的全部搜索路径,路径与路径之间使用冒号分隔:


pkg-config的搜索路径

/usr/lib/pkgconfig/usr/share/pkgconfig为例来看看搜索目录下的内容,可以看到这些目录下存放的全部都是.pc文件:

/usr/lib/pkgconfig 和 /usr/share/pkgconfig目录

另外,定义中还提到了PKG_CONFIG_PATH,这是pkg-config的环境变量,具体内容会在8.5中介绍。

8.4 操作步骤


这一步的步骤非常简单,将opencv.pc复制到pkg-config的任意一个搜索路径中即可,我选择的目录是/usr/lib/pkgconfig,用户可以选择自己喜欢的目录。

 

使用cp命令将OpenCV生成的opencv.pc文件复制到/usr/lib/pkgconfig目录下,顺便给文件改名为opencv-3-4-10d.pc。前文提到过,OpenCV2.x和3.x生成的.pc文件都叫opencv.pc,为了区分不同版本和编译模式生成的文件,我在这里修改了文件名


复制opencv.pc文件并重命名

复制完成之后,可以使用pkg-config命令来验证一下配置是否成功。输入pkg-config --modversion <package name>pkg-config --cflags <package name>pkg-config --libs <package name>进行测试,<package name>是.pc文件去掉后缀的名称,这里是opencv-3-4-10d,记得不要写成opencv了。

 

验证配置是否生效

如果命令成功输出了.pc文件中的内容,这一步就完成了。
 

8.5 PKG_CONFIG_PATH


最后简单介绍一下8.3节定义中提到的PKG_CONFIG_PATH,它是pkg-config的环境变量(定义来自$man pkg-config)

It will additionally  look in the colon-separated (on Windows, semicolon-separated) list of directories specified by the PKG_CONFIG_PATH environment variable.

 
一些教程在这一步使用了PKG_CONFIG_PATH来设置.pc文件的路径。在/etc/bash.bashrc文件末尾添加 PKG_CONFIG_PATH=$PKG_CONFIG_PATH:<path to .pc file>export PKG_CONFIG_PATH两行,之后输入source /etc/bash.bashrc使写入的内容生效。

/etc/bash.bashrc末尾追加语句

source /etc/bash.bashrc

这种做法也是没有问题的,由定义可知,pkg-config除去搜索/usr/lib/pkgconfig等默认目录之外,还会搜索环境变量PKG_CONFIG_PATH中设置的.pc文件路径 。

不过,如果要使用这种方法来设置多个.pc文件的路径,记得使用英文冒号(Windows中是分号)将不同的文件路径分隔开,并且给.pc文件设置不同的文件名称


更新文件名数据库


第九步: 更新系统中的文件名数据库
命令执行位置: 无要求
命令行:
$ sudo updatedb
注意:
1. locate命令

复制

最后,运行一个很简单的命令sudo updatedb更新系统中的文件名数据库


sudo updatedb

updatedb属于GNU Findutils中的一个命令工具。Findutils是一个GNU基本目录搜索包,包中提供了例如find、locate、update和xargs这类定位工具(https://www.gnu.org/software/findutils/)。
 

The updatedb program updates the file name database used by the locate program. The file name database contains lists of files that were in particular directory trees when the databases were last updated.

  
举个例子,当我们编译完OpenCV并生成了opencv-3-4-10d.pc文件之后,如果没有更新文件名数据库,那么使用locate定位该文件的位置是没有结果的,因为文件路径还没有被记录到数据库中。而当我们使用了sudo updatedb命令更新了数据库之后,再次使用locate函数,就会输出.pc文件的具体路径了

sudo update和locate命令

这一步并不是在配置文件,只是将OpenCV新生成的文件名及其路径记录在系统的文件名数据库中,方便以后进行文件定位和查找

测试


第十步: 测试核心算法和额外算法
命令执行位置: <opencv_source_directory>/samples/cpp/
命令行:
$ sudo g++ -o <executable program name> <source code file> `pkg-config --cflags --libs <.pc filename>`
$ sudo ./<executable program name>
注意:
1. 可以新建源代码文件进行测试, 也可以使用OpenCV自带的样例程序

复制

最后来测试一下我们安装的OpenCV是否可以成功运行,OpenCV提供了一个名为samples的文件夹,里面存放了许多样例程序,samples位于OpenCV核心算法源代码文件夹下(注意不是opencv_contrib文件夹)
 
进入samples文件夹下,可以看到java、python、c++等各类语言的测试程序文件夹,我们使用cpp文件夹下的c++程序进行测试。

~/samples/cpp文件夹

10.1 核心算法

先来测试核心算法模块,我选择em.cpp来执行EM聚类算法

首先输入sudo g++ -o test_em em.cpp `pkg-config --cflags --libs opencv-3-4-10d`进行源代码编译。g++是在GNU/Linux系统下常用的C++编译器;-o选项可以指定生成的可执行文件名称,我将文件名设置为test_em;em.cpp是需要编译的源代码文件名。

之后的一长串是pkg-config语句,我们在第8节执行过这个命令,该命令会输出debug版OpenCV3.4.10的头文件和库文件信息,有一点需要注意,pkg-config语句外的那个符号不是单引号,它是键盘中和~在一起的符号`,常常位于数字1的左边

源代码编译

源代码编译成功之后,再次查看cpp文件夹,会发现多了一个名为test_em的绿色文件,这就是em.cpp编译生成的可执行程序了。

之后使用命令sudo ./test_em执行该程序,如果成功输出下方的图像,则代表测试成功。

测试em算法

10.2 额外算法


接下来测试额外算法模块,我选择的是samples/cpp/tutorial_code/xfeatures2D目录下的程序。该文件夹下只有一个源文件LATCH_match.cpp,用于实现LATCH匹配算法。


输入sudo g++ -o LATCH_match LATCH_match.cpp `pkg-config --cflags --libs opencv-3-4-10d`来编译源代码,我将生成的可执行程序命名为LATCH_math;之后使用sudo ./LATCH_match命令执行程序即可。


由于找不到图片而报错

上图的报错是因为可执行程序未找到需要载入的图片和文件,程序运行需要的2张图片和1个XML文件都保存在samples/data下。我们需要将这些图片和数据与可执行程序放置在同一目录下

复制图片和数据至测试目录下

放置好数据和图片之后再次测试,就可以成功输出图片了。这里还有一点需要注意,由于文件权限的问题,最好在运行可执行程序时加上sudo语句,便于程序输出结果的保存

拿这个例子来说,如果只用./LATCH_match命令运行程序的话,程序生成的结果图片会因为权限不够的问题无法保存,下图橙色框中标注出的就是程序警告信息"can't open file for writing: permission denied":

由于权限不够无法保存图片

使用OpenCV自带的样例来测试是最方便的方法,如果用户想要自己写一个简单的程序来测试也是可以的。



以上就是Debug版本的OpenCV安装与配置的最后一节了 这一篇主要是在做编译后的一些配置任务,虽然步骤很简单但是很重要。每一个步骤也有多种方法可以选择。


下一篇是Release版本OpenCV3.4.10+contrib编译和配置步骤 从第三步"新建构建目录"开始,一直到第十步"测试"结束。由于具体的操作及命令解释在前几篇文中已经详细地介绍了,所以下一篇仅展示步骤截图并搭配简单的说明,欢迎继续收看


~END~

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

评论