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.pswp.cn/news/532721.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532721.shtml
英文地址,請注明出處:http://en.pswp.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。 …