Linux下编译、链接、加载运行C++ OpenCV的两种方式及常见问题的解决

Linux下编译、链接、加载运行C++ OpenCV的两种方式及常见问题的解决

在Linux下安装完OpenCV C++之后(还没有安装的读者请参考Ubuntu 18.04 安装OpenCV C++),本文将探索Linux下编译、链接C++ OpenCV的两种方式,并且给出笔者在初次尝试时遇到的一些问题的解决方法。一般来看,不只是OpenCV,其实本文已经囊括了大部分Linux下C++链接库文件、运行时链接动态库文件的常见问题。各位读者如果链接时遇到其他问题,也可留言讨论。

注意,我们这里并不采用简单的包含进opencv的头文件,然后再main函数中打印个hello world的测试方式。这种测试方式只能测试头文件的正常包含,即只能保证编译通过,我们需要实际地调用一些opencv中的图像处理接口,来保证链接和运行时的正确性。这里,我们调用Canny算子来提取图像的边缘信息。如果这个测试用例能够正常地编译、链接、运行的话,那整个opencv的运行测试才能算是完整通过了。

首先我们准备一个测试源码demo.cpp,和测试图像demo.jpg,把它们放到测试文件夹demo/下。即一开始,我们有目录树如下:

├── demo
│   ├── demo.cpp
│   └── demo.jpg

方法一:CMake

CMake链接的使用方法笔者已经在安装OpenCV的文章中介绍过,这里再复述一遍,这种方法基本不会遇到什么问题。我们先准备一个CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project( demo )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( demo demo.cpp )
target_link_libraries( demo ${OpenCV_LIBS} )

具体的含义笔者就不在这里赘述了,这需要一些cmake的相关知识,总之按照这个CMakeLists.txt是可以正常编译链接运行包含opencv库的源代码的。我们来试一下:

cmake .
make

过程输出:

$ cmake .
-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found OpenCV: /usr/local (found version "4.5.4")
-- Configuring done
-- Generating done
-- Build files have been written to: /home/song/hello/demo/demo
$ make
Scanning dependencies of target demo
[ 50%] Building CXX object CMakeFiles/demo.dir/demo.cpp.o
[100%] Linking CXX executable demo
[100%] Built target dem

经过这两步后,我们直接运行生成的可执行文件demo

./demo

会得到一张Canny算子提取的图像边缘信息Canny.jpg,整个过程没有报错的话,则测试成功。

方法二:通过g++直接命令行编译

笔者在使用这种方法时遇到了不少问题,会记录在后面的常见问题及解决一节,读者在编译过程中遇到问题可以去后面看一下,如果后面也没有你遇到的问题,欢迎留言讨论。

我们回到最初的测试目录的内容,只有demo.cppdemo.jpg

我们先尝试直接编译链接:

g++ demo.cpp -o demo

这样是肯定不行的,会报一大堆undefined reference,因为这样是没有链接我们的opencv库的。但是只这样编译其实是可以的,即:

g++ -c demo.cpp

除非你的头文件都找不到,否则上述-c选项的仅编译的命令是会通过的,会得到一个demo.o可重定向文件。头文件找不到保存请看下面的问题一。

下面我们来解决链接时undefined reference的问题,未定义引用,究其原因无非就是opencv的库文件没有链接进来。对于动态链接库,我们通常使用-l[lib]的选项来链接,但是opencv中要包含的库文件太多了,我们难道要一个一个写吗?

当然不用!我们通常会借助pkg-config工具来生成链接时的库文件选项。如果还没有安装请参考问题二。我们要在pkgconfig的目录下添加opencv.pc来让它帮助生成我们的opencv链接选项。opencv.pc应该是在opencv安装时直接生成的。

但默认是不生成的,笔者当时安装的时候不知道要用到这个,就没有配置,笔者就自己从Stack Overflow抄了个opencv.pc文件,但是弄了大半天都不行,最后才发现是版本太老了,不适合现在的opencv版本了。最终无奈自己写了个脚本把lib目录下opencv的动态链接库名称都提取出来,放到opencv.pc里才成功。(不然这篇博客应该会早几小时出来,本段小吐槽勿怪

笔者把自己提取到的opencv.pc放到问题三了,可能与官网安装时生成的不同,但是亲测使用正常,有需要的小伙伴自取,版本是4.5.4。

将适合自己版本的opencv.pc放到/usr/local/lib/pkgconfig目录下。然后命令行执行pkg-config opencv --libs --cflags,应当会得到如下链接选项:

-I/usr/include/opencv -I/usr/include/opencv2 -L/usr/local/lib -lopencv_aruco -lopencv_barcode -lopencv_bgsegm -lopencv_bioinspired -lopencv_calib3d -lopencv_ccalib -lopencv_core -lopencv_datasets -lopencv_dnn_objdetect -lopencv_dnn -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_features2d -lopencv_flann -lopencv_freetype -lopencv_fuzzy -lopencv_gapi -lopencv_hfs -lopencv_highgui -lopencv_imgcodecs -lopencv_img_hash -lopencv_imgproc -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_ml -lopencv_objdetect -lopencv_optflow -lopencv_phase_unwrapping -lopencv_photo -lopencv_plot -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_shape -lopencv_stereo -lopencv_stitching -lopencv_structured_light -lopencv_superres -lopencv_surface_matching -lopencv_text -lopencv_tracking -lopencv_videoio -lopencv_video -lopencv_videostab -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_ximgproc -lopencv_xobjdetect -lopencv_xphoto

这时我们就可以正常地链接测试源码demo.cpp了:

g++ demo.cpp `pkg-config opencv --libs --cflags` -o demo

注意是反引号:`。

关于以上链接选项的稍微详细一些的介绍,可以参考:gcc参数 -i, -L, -l, -include。

这时我们就应该得到可执行文件demo了,运行它,我们可以得到一张Canny算子提取的图像边缘信息Canny.jpg,整个过程没有报错的话,则测试成功。

如果已经得到了可执行文件demo,但是运行时报错找不到共享库,请参考问题四。

常见问题及解决

问题一:默认安装的头文件路径与搜索的头文件路径不匹配

找不到头文件报错,通常是因为默认安装的头文件路径与搜索的头文件路径不匹配。opencv默认安装的头文件路径是/usr/local/include,而我们搜索的默认路径在/usr/include

遇到这种找不到头文件的报错,请先到/usr/local/include/opencv4/opencv2路径下确认有自己的头文件,然后直接软链接就行了:

sudo ln -s /usr/local/include/opencv4/opencv2 /usr/include/

关于软链接,用法:Linux软链接的使用,详解:Linux中的硬链接和软链接。

或者通过gcc的-I参数来指定头文件的搜索路径:

g++ -c demo.cpp -I/usr/local/include

问题二:pkg-config的安装

下载、解压、安装、验证一气呵成:

# 下载
wget https://pkg-config.freedesktop.org/releases/pkg-config-0.29.2.tar.gz
# 解压
tar -zxvf pkg-config-0.29.2.tar.gz 
# 安装
cd pkg-config-0.29.2/
./configure 
make
make check
sudo make install
# 验证
pkg-config --version
# 输出:0.29.2 安装成功

问题三:OpenCV 4.5.4 可行的opencv.pc文件

这个是笔者自己写脚本提取的opencv.pc文件,可能与官网安装时生成的不同,但是亲测使用正常,放到/usr/local/lib/pkgconfig目录下即可。

prefix=/usr
exec_prefix=${prefix}/local
includedir=${prefix}/include
libdir=${exec_prefix}/libName: opencv
Description: The opencv library
Version: 2.x.x
Cflags: -I${includedir}/opencv -I${includedir}/opencv2
Libs: -L${libdir} -lopencv_aruco -lopencv_barcode -lopencv_bgsegm -lopencv_bioinspired -lopencv_calib3d -lopencv_ccalib -lopencv_core -lopencv_datasets -lopencv_dnn_objdetect -lopencv_dnn -lopencv_dnn_superres -lopencv_dpm -lopencv_face -lopencv_features2d -lopencv_flann -lopencv_freetype -lopencv_fuzzy -lopencv_gapi -lopencv_hfs -lopencv_highgui -lopencv_imgcodecs -lopencv_img_hash -lopencv_imgproc -lopencv_intensity_transform -lopencv_line_descriptor -lopencv_mcc -lopencv_ml -lopencv_objdetect -lopencv_optflow -lopencv_phase_unwrapping -lopencv_photo -lopencv_plot -lopencv_quality -lopencv_rapid -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_shape -lopencv_stereo -lopencv_stitching -lopencv_structured_light -lopencv_superres -lopencv_surface_matching -lopencv_text -lopencv_tracking -lopencv_videoio -lopencv_video -lopencv_videostab -lopencv_wechat_qrcode -lopencv_xfeatures2d -lopencv_ximgproc -lopencv_xobjdetect -lopencv_xphoto

问题四:可执行文件运行时找不到共享库

由于我们Linux默认是动态链接的,即有些共享库是在可执行文件运行时才链接进来的(关于链接、装载与库,可参考:Linux下的ELF文件、链接、加载与库(含大量图文解析及例程)。因此我们正确地链接生成可执行文件demo之后并不能保证正确地运行,可能会找不到共享库报错:

./demo: error while loading shared libraries: libopencv_core.so.4.5: cannot open shared object file: No such file or directory

我们还可以通过ldd命令来查看可执行文件所需要的共享库:

$ ldd demolinux-vdso.so.1 (0x00007ffdd25b5000)libopencv_core.so.4.5 => not foundlibopencv_imgcodecs.so.4.5 => not foundlibopencv_imgproc.so.4.5 => not foundlibstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fdf87e92000)libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fdf87c7a000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdf87889000)libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fdf874eb000)/lib64/ld-linux-x86-64.so.2 (0x00007fdf8841f000

确实opencv相关的库都找不到,但是这时我们到共享库目录/usr/local/lib/下去查看,其实是有这个共享库的:

$ ls -l /usr/local/lib/ | grep "core"
lrwxrwxrwx 1 root root         21 107 19:55 libopencv_core.so -> libopencv_core.so.4.5
lrwxrwxrwx 1 root root         23 107 19:55 libopencv_core.so.4.5 -> libopencv_core.so.4.5.4
-rw-r--r-- 1 root root    5247960 107 11:42 libopencv_core.so.4.5.4

既然有这个库还报找不到文件的错误,那这就提醒我们,是不是系统不知道要到这个目录下去找共享库。这时,我们就应该通过指定环境变量LD_LIBRARY_PATH来告诉系统我们想要搜索的共享库目录。即通过以下命令将/usr/local/lib添加到共享库搜索目录的环境变量中:

export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

添加之后,我们可以直接先ldd来查看一下是否已经能够找到共享库:

$ ldd demolinux-vdso.so.1 (0x00007ffc15975000)libopencv_core.so.4.5 => /usr/local/lib/libopencv_core.so.4.5 (0x00007fb271fde000)libopencv_imgcodecs.so.4.5 => /usr/local/lib/libopencv_imgcodecs.so.4.5 (0x00007fb271b1f000)libopencv_imgproc.so.4.5 => /usr/local/lib/libopencv_imgproc.so.4.5 (0x00007fb271283000)libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb270efa000)libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb270ce2000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb2708f1000)libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fb2706ed000)libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb2704ce000)librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fb2702c6000)libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fb2700a9000)libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb26fd0b000)libjpeg.so.8 => /usr/lib/x86_64-linux-gnu/libjpeg.so.8 (0x00007fb26faa3000)libpng16.so.16 => /usr/lib/x86_64-linux-gnu/libpng16.so.16 (0x00007fb26f871000)libtiff.so.5 => /usr/lib/x86_64-linux-gnu/libtiff.so.5 (0x00007fb26f5fa000)/lib64/ld-linux-x86-64.so.2 (0x00007fb27282d000)liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007fb26f3d4000)libjbig.so.0 => /usr/lib/x86_64-linux-gnu/libjbig.so.0 (0x00007fb26f1c6000)

我们看到,所需的共享库已经全部能够找到了。这时我们再运行,即可得到正确结果。

其实总的来说,这里的问题一对应的是编译时期头文件包含的问题,问题二三对应的是链接时期使用pkg-conifg生成对应库文件的链接选项的问题,而问题四对应的则是运行时期共享库搜索的环境变量配置的问题。所以说本文的这一节将一个动态链接的C++库在Linux下编译、链接、加载运行各个阶段会出现的常见问题都涵盖到了。

总之以上就是笔者在编译、链接、加载运行含有OpenCV库的源代码时遇到的一些问题及解决方案了,若有错误遗漏,或读者如果有其他问题不能解决,欢迎留言讨论。

Ref

https://blog.csdn.net/Charliewolf/article/details/101273248

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532721.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win10无法检验服务器出示的ssl证书,win10系统网站启用ssL安全证书的操作方法

win10系统网站启用ssL安全证书的操作方法?很多win10用户在使用电脑的时候,会发现win10系统网站启用ssL安全证书的的现象,根据小编的调查并不是所有的朋友都知道win10系统网站启用ssL安全证书的的问题怎么解决,不会的朋友也不用担心&#xff…

Linux下构建自己的C++共享库并配合pkg-config生成链接选项

Linux下构建自己的C共享库并配合pkg-config生成链接选项 本文将以C链表的新建、打印操作为例构建自己的共享库,并在实际调试代码时尝试使用。我们在做数据结构题时经常需要将链表打印出来看一下结果,但是并没有一种库函数可以让我们直接调用来打印自己的…

webkitlineclamp css3,-webkit-line-clamp

无标题文档static:对象遵循常规流。top,right,bottom,left等属性不会被应用。 relative: 对象遵循常规流,并且参照自身在常规流中的位置通过top,right,bottom,left属性进…

Linux内核初探

Linux内核初探 内核的组成部分 kernel:内核核心文件,一般为bzp_w_picpath,经过压缩处理的镜像文件;通常内核核心文件保存在/boot/目录下,名称为vmlinuz-version-release kernel object(ko):内核对象&…

Nplayer本地文件拷到服务器,手把手教你简易NAS构建,手机/平板/智能电视随意调取,家庭存储云共享,有了自己的网络云盘后再也不用担心容量不够了!...

之前嫌键盘侠烦,写这些也没意义所以把账号注销了文章删除了,现在想了想我抗吧12级老蛆还喷不过这帮小兔崽子?换了skt.ruo秽土转生,求喷子和我在各评论对线。特别是匿名dog见一个怼死一个。下面是之前号写的内容原文 -#简介NAS全称…

gdb 入门

gdb 入门 简介 gdb是GNU开源组织发布的一个强大的Linux下的程序调试工具。 一般来说,GDB主要帮助你完成下面四个方面的功能: 1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。 2、可让被调试的程序在你所指定的调置的断点…

视频监控系统中的平台服务器,【视频监控主机 网络视频集中管理平台服务器】 - 太平洋安防网...

完善的管理功能管理系统内所有设备的接入及设备权限。设备状态监视。系统资源及用户权限分配及系统抢权管理。电子地图。实现系统内视频流的管理和转发控制。可通过WEB远程管理。强大的报警事件管理功能系统具备完善的报警及处理功能,能根据预先编写事件 处理预案对…

Linux下的CUDA多版本管理

Linux下的CUDA多版本管理 关于CUDA、cuDNN等的简介和安装可参考:显卡、显卡驱动、CUDA、CUDA Toolkit、cuDNN 梳理。 CUDA多版本 有时我们会在一台机器上同时看到多个版本的CUDA,比如nvcc -V和nvidia-smi的输出就可能会不同: 在我们实验室…

电脑显示无法连接sql服务器,他人的电脑为什么无法连接我电脑上的sql sever服务器...

如果SQL2005连接不上,并且服务器上所有与防火相关的东西都关闭了,还是连接不上。进行如下操作:一、为 SQL 启用远程连接1. 单击“开始”,依次指向“程序”、“Microsoft SQL Server 2005”和“配置工具”,然后单击“SQL Server 外…

ONNX初探

ONNX初探 转载自:https://blog.csdn.net/just_sort/article/details/112912272 0x0. 背景 最近看了一些ONNX的资料,一个最大的感受就是这些资料太凌乱了。大多数都是在介绍ONNX模型转换中碰到的坑点以及解决办法。很少有文章可以系统的介绍ONNX的背景…

服务器修改地址,服务器修改管理地址

服务器修改管理地址 内容精选换一换在弹性云服务器上安装完成后输入公网IP,无法连接目的虚拟机,端口无法访问工具。源端网络未连通目的端。目的端安全组未开放8084端口。目的端网络ACL禁用了8084端口。登录源端服务器后,在源端服务器中ping 目…

ONNX再探

ONNX再探 本文转自:https://blog.csdn.net/just_sort/article/details/113802330 这篇文章从多个角度探索了ONNX,从ONNX的导出到ONNX和Caffe的对比,以及使用ONNX遭遇的困难以及一些解决办法,另外还介绍了ONNXRuntime以及如何基于…

图像卷积及其计算(特征图尺寸、参数量、计算量)

图像卷积及其计算(特征图尺寸、参数量、计算量) 卷积前后特征图尺寸的计算 定义参数如下: 输入特征图尺寸: WWWWWW卷积核尺寸: FFFFFF步长: SSS填充的像素数:PPP 则有输出特征图尺寸为 NNNN…

图解自监督学习(CV)

图解自监督学习(CV) 译自:https://amitness.com/2020/02/illustrated-self-supervised-learning/ 作者:Amit Chaudhary 注:译者在某些地方对原文的表述做了调整,使其适合汉语的阅读习惯,并在…

机器学习中的归纳偏置

机器学习中的归纳偏置 带着偏见看世界,否则你根本没有看待世界的方式。 本文主要参考整理自知乎问题:如何理解Inductive bias? No-Free-Lunch(NLF)定理指出学习是不可能的,除非有先验知识。通常情况下&…

编译型与解释型、动态语言与静态语言、强类型语言与弱类型语言概念辨析

编译型与解释型、动态语言与静态语言、强类型语言与弱类型语言概念辨析 转自:https://blog.csdn.net/u010533843/article/details/76215487 编译型和解释型 我们先看看编译型,其实它和汇编语言是一样的:也是有一个负责翻译的程序来对我们的…

Linux环境变量详解

Linux环境变量详解 环境变量是操作系统环境设置的变量,适用于整个系统的用户进程。 环境变量分类 按照权限分类 系统级:系统级的环境变量是每个登录到系统的用户都要读取的系统变量用户级:用户级的环境变量则是该用户使用系统时加载的环境…

[分布式训练] 单机多卡的正确打开方式:PyTorch

[分布式训练] 单机多卡的正确打开方式:PyTorch 转自:https://fyubang.com/2019/07/23/distributed-training3/ PyTorch的数据并行相对于TensorFlow而言,要简单的多,主要分成两个API: DataParallel(DP&am…

上学期C语言复习

C语言&#xff1a;面向过程例&#xff1a;完成两个单元内容的交换 &#xff1a; #include<stdio.h> //定义一个完成两个数据交换的函数 //void swap(int m,int n) void swap(int*m,int* n) { int temp;//临时单元 temp*m; *m*n; *ntemp; } int main() {int a5,b10; print…

[分布式训练] 单机多卡的正确打开方式:Horovod

[分布式训练] 单机多卡的正确打开方式&#xff1a;Horovod 转自&#xff1a;https://fyubang.com/2019/07/26/distributed-training4/ 讲完了单机多卡的分布式训练的理论、TensorFlow和PyTorch分别的实现后&#xff0c;今天瓦砾讲一个强大的第三方插件&#xff1a;Horovod。 …