目錄
引言
一、第一步:萬事開頭難 - 準備工作
1.1 獲取并“安裝”OpenCV
1.2 創建一個新的Qt項目
1.3 建立專業的項目目錄結構
二、第二步:核心操作 - 配置.pro文件
2.1 方式一:圖形化向導(適合初次體驗)
2.2 方式二:手動編輯.pro文件(專業且靈活)
三、第三步:小試牛刀 - 編寫代碼并編譯
3.1 修改`main.cpp`
3.2 編譯項目
四、第四步:臨門一腳 - 運行與問題排查
4.1 問題根源:編譯時鏈接 vs 運行時加載
4.2 解決方案
4.2.1 方案一:簡單粗暴法 - 手動復制DLL
4.2.2 方案二:Qt Creator的優雅之道 - 配置運行環境
4.2.3 方案三:終極方案 - 編寫構建后腳本(推薦)
總結
??🎬 攻城獅7號:個人主頁
🔥 個人專欄:C++QT跨平臺界面編程
?? 君子慎獨!
?🌈 大家好,歡迎來訪我的博客!
?? 此篇文章主要介紹?Qt Creator如何引入第三方庫
📚 本期文章收錄在《C++QT跨平臺界面編程》,大家有興趣可以自行查看!
?? 歡迎各位 ?? 點贊 👍 收藏 ?留言 📝!
引言
????????在軟件開發的世界里,幾乎沒有哪個大型項目是完全從零開始、閉門造車完成的。無論是為了實現復雜的功能,還是為了加快開發速度,我們都不可避免地需要站在巨人的肩膀上——使用第三方庫。對于C++開發者,尤其是使用Qt框架構建圖形化界面(GUI)應用的工程師來說,掌握如何優雅、高效地將強大的第三方庫集成到自己的項目中,是一項至關重要的核心技能。
????????OpenCV(Open Source Computer Vision Library)作為計算機視覺領域最負盛名、功能最強大的開源庫,是無數圖像處理、機器學習、視頻分析應用的首選。而Qt則以其跨平臺、功能完善、開發體驗優秀而著稱。將OpenCV強大的計算能力與Qt精美的交互界面相結合,便能創造出專業、強大的桌面應用程序。
????????然而,對于許多初學者來說,配置過程中的各種路徑問題、鏈接器錯誤、運行時DLL丟失等問題,常常像一道道難以逾越的鴻溝,令人望而生畏。本教程的目的,就是為您徹底掃清這些障礙。
????????我們將以一個全新的Qt Widgets項目為例,手把手、一步步地演示如何將OpenCV庫集成進來。本教程不僅僅是步驟的羅列,更會深入解釋每個步驟背后的“為什么”,讓您知其然,更知其所以然。讀完本篇文章,您將掌握:
????????(1)規范的項目文件組織方式:學習如何管理第三方庫文件,讓您的項目結構清晰、可移植。
????????(2)Qt項目文件(.pro)的核心配置:精通`INCLUDEPATH`(頭文件路徑)和`LIBS`(庫文件)的設置,包括如何使用相對路徑和進行Debug/Release的區分配置。
????????(3)解決經典的運行時DLL丟失問題:深入理解動態鏈接庫(DLL)的加載機制,并學會三種以上解決該問題的有效方法。
????????(4)編寫簡單的測試代碼驗證集成效果:通過一個“打開圖片并顯示”的簡單實例,完成從配置到運行的閉環。
????????準備好了嗎?讓我們開始這段奇妙之旅吧!
一、第一步:萬事開頭難 - 準備工作
????????在敲下第一行配置代碼之前,我們需要做好充分的準備。這包括準備OpenCV庫文件、創建一個新的Qt項目以及建立一個科學合理的文件目錄結構。
1.1 獲取并“安裝”OpenCV
????????首先,您需要從[OpenCV官方網站](https://opencv.org/releases/)下載適用于您開發環境(例如Windows)的預編譯版本。官網默認提供的是 MSVC 版本。下載下來通常是一個可執行文件,運行它,其實質是一個自解壓程序,會將其中的文件解壓到您指定的目錄。
????????解壓后,您會得到一個名為`opencv`的文件夾,其核心內容位于`build`子目錄中。我們需要其中的三個部分:
????????- ? `opencv/build/include`: 這里存放著所有的OpenCV頭文件(`.h`和`.hpp`)。
????????- ? `opencv/build/x64/vc15/lib` (路徑中的`x64/vc15`可能因您的系統和編譯器版本而異): 這里存放著鏈接時所需的庫文件(`.lib`)。
????????- ? 通常您會看到兩個版本,如`opencv_world320.lib`(用于Release模式)和`opencv_world320d.lib`(用于Debug模式,注意末尾的'd')。
????????- ? `opencv/build/x64/vc15/bin`: 這里存放著程序運行時真正依賴的動態鏈接庫文件(`.dll`)。
1.2 創建一個新的Qt項目
打開Qt Creator,創建一個新的項目:
(1)`File` -> `New Project`
(2)選擇 `Application (Qt)` -> `Qt Widgets Application`。
(3)為項目命名,例如`testqt`,并選擇一個項目創建路徑。
(4)選擇構建系統為`qmake`。
(5)其他步驟保持默認設置,一直點擊“Next”直到完成。
1.3 建立專業的項目目錄結構
????????這是至關重要的一步,一個好的目錄結構能讓您的項目瞬間變得專業和易于管理。根據您提供的示例,我們將采用一種常見的源碼與依賴分離的結構。
????????假設您的項目完整路徑為 `D:/MyProjects/testqt/`。我們在此根目錄下創建如下結構:
D:/MyProjects/
|-- 3rdparty/ ? ? ? ? ? ? ? ? <-- 新建一個文件夾,統一存放所有第三方庫
| ? |-- opencv/
| ? ? ? |-- include/ ? ? ? ? ?<-- 用于存放OpenCV的頭文件
| ? ? ? |-- lib/ ? ? ? ? ? ? ?<-- 用于存放OpenCV的.lib文件
| ? ? ? |-- bin/ ? ? ? ? ? ? ?<-- 用于存放OpenCV的.dll文件
|
|-- testqt/ ? ? ? ? ? ? ? ? ? <-- 這是我們的Qt項目目錄
| ? |-- testqt.pro ? ? ? ? ? ?<-- Qt項目配置文件
| ? |-- main.cpp
| ? |-- widget.h
| ? |-- widget.cpp
| ? |-- widget.ui
????????然后,將我們之前從OpenCV解壓目錄中找到的文件,按需復制過來:
(1)將`opencv/build/include`下的所有內容,復制到 `D:/MyProjects/3rdparty/opencv/include/` 目錄下。
(2)將`opencv/build/x64/vc15/lib`下的`opencv_world320.lib`和`opencv_world320d.lib`,復制到 `D:/MyProjects/3rdparty/opencv/lib/` 目錄下。
(3)將`opencv/build/x64/vc15/bin`下的`opencv_world320.dll`和`opencv_world320d.dll`,復制到 `D:/MyProjects/3rdparty/opencv/bin/` 目錄下。
????????為什么要這樣做?
(1)可移植性:`testqt`項目通過相對路徑引用`3rdparty`中的庫,只要保持這個相對文件結構,您可以將`MyProjects`這個根目錄拷貝到任何電腦上,項目都能直接編譯運行。
(2)版本鎖定:項目使用的OpenCV版本被清晰地鎖定在`3rdparty`中,避免了系統環境變量中可能存在的其他版本干擾。
(3)結構清晰:項目代碼(`testqt`)與第三方依賴(`3rdparty`)完全分離,一目了然。
準備工作完成!我們的項目現在“萬事俱備,只欠東風”——配置`.pro`文件。
二、第二步:核心操作 - 配置.pro文件
????????`.pro`文件是Qt項目的“心臟”,它通過`qmake`工具告訴編譯器如何構建我們的應用程序。我們需要在這里告訴編譯器兩件重要的事情:
? ? ? ? (1)去哪里找OpenCV的頭文件(`INCLUDEPATH`)。
? ? ? ? (2)需要鏈接哪個OpenCV的庫文件(`LIBS`)。
????????我們介紹兩種配置方式:圖形化向導和手動編輯。強烈推薦學習并使用第二種手動編輯的方式。
2.1 方式一:圖形化向導(適合初次體驗)
????????Qt Creator提供了一個方便的向導來添加庫。
(1)在項目文件樹上右鍵點擊項目根節點,選擇`Add Library...`。
(2)選擇`External Library`,點擊`Next`。
(3)在`Library file`字段,點擊`Browse...`,導航到我們項目中的`3rdparty/opencv/lib/`目錄,選擇`opencv_worldXXX.lib`(先選Release版本的)。
(4)在`Include path`字段,`Browse...`到`3rdparty/opencv/include/`目錄。
(5)關鍵:在`Platform`下拉菜單中,確保勾選了`Windows`(如果您在Windows開發)。取消勾選其他平臺。
(6)重要:取消勾選`Add "d" as a suffix for debug version`。因為我們稍后會通過更靈活的方式來手動區分Debug和Release版本,這里不使用它的自動功能。
(7)點擊`Next`,然后`Finish`。
????????此時,打開`.pro`文件,您會看到Qt Creator自動為您添加了類似下面(路徑可能是絕對路徑)的代碼:
????????這種方法的缺點是,它可能會生成硬編碼的絕對路徑,不利于項目遷移。因此,我們更推薦下面的手動方式。
2.2 方式二:手動編輯.pro文件(專業且靈活)
????????手動編輯能讓我們對項目有完全的控制,尤其是使用相對路徑,這才是專業的做法。
打開`testqt.pro`文件,在文件的末尾添加以下內容,并做更完善的Debug/Release區分處理。
# ===================================================================# OpenCV Configuration# ===================================================================# $$PWD 是一個qmake內置變量,代表.pro文件所在的當前目錄(D:/MyProjects/testqt/)。# 我們使用 '..' 來向上追溯一級目錄,從而定位到3rdparty文件夾。# 這種相對路徑的寫法,保證了項目的可移植性。# 1. 指定頭文件路徑INCLUDEPATH += $$PWD/../3rdparty/opencv/include# 2. 指定庫文件路徑和具體庫文件# 使用CONFIG來實現Debug和Release模式的區分配置CONFIG(debug, debug|release) {# Debug模式下# -L: 指定庫文件所在的目錄 (L for Library Path)# -l: 指定具體的庫文件名,省略前綴'lib'和后綴'.lib' (l for library)# 例如 opencv_world320d.lib -> -lopencv_world320dLIBS += -L$$PWD/../3rdparty/opencv/lib -lopencv_world320d} else {# Release模式下LIBS += -L$$PWD/../3rdparty/opencv/lib -lopencv_world320}
> 代碼解讀:
> - ? `$$PWD/../3rdparty/opencv/lib`:這是精髓所在。`$$PWD`是`D:/MyProjects/testqt/`,`..`讓路徑上溯一層到`D:/MyProjects/`,然后再進入`3rdparty/opencv/lib`。這樣無論`MyProjects`目錄在哪里,路徑都是正確的。
> - ? `INCLUDEPATH += ...`:將OpenCV `include`目錄添加到項目的頭文件搜索路徑列表中。編譯器在編譯時,會到這個目錄下去尋找`#include`的頭文件。
> - ? `CONFIG(debug, debug|release) { ... } else { ... }`:這是一個條件判斷語句。當項目以Debug模式構建時(`debug`條件成立),執行第一個代碼塊;當以Release模式構建時,執行`else`中的代碼塊。
> - ? `LIBS += -L<path> -l<name>`:這是鏈接器指令。
> ? ? - ? `-L`后面跟著的是庫文件所在的目錄路徑。
> ? ? - ? `-l`后面跟著的是**庫的名稱**(去掉了`lib`前綴和`.lib`或`.a`后綴)。鏈接器會根據這個名稱自動尋找對應的文件(如`libopencv_world455d.lib`)。
????????完成編輯后,務必執行qmake。右鍵點擊項目根節點,選擇`Run qmake`。這一步會使您的`.pro`文件修改生效,重新生成Makefile。
????????至此,編譯環境已經配置完畢。如果現在點擊“編譯”,只要代碼中沒有語法錯誤,項目應該能夠成功通過編譯,不會再報“找不到頭文件”或“未定義的引用”這類鏈接錯誤了。
三、第三步:小試牛刀 - 編寫代碼并編譯
????????配置完成,是時候寫幾行代碼來驗證我們的勞動成果了。根據您在`qtcreator引入第三方opencv庫和頭文件路徑.md`中的描述,我們進行一個最簡單的測試:在程序啟動時,直接調用OpenCV的函數來創建一個窗口。
????????我們將修改`main.cpp`文件,因為這個測試不依賴于`widget.ui`上的任何控件。
3.1 修改`main.cpp`
????????打開`main.cpp`,添加OpenCV的頭文件,并在顯示主窗口前加入OpenCV的測試代碼。
// main.cpp#include "widget.h"#include <QApplication>// 1. 引入OpenCV核心頭文件#include <opencv2/opencv.hpp>int main(int argc, char *argv[]){QApplication a(argc, argv);// 2. 添加OpenCV測試代碼// 使用cv命名空間// 創建一個名為 "open cv" 的窗口cv::namedWindow("open cv");Widget w;w.show();// 3. 最終返回Qt事件循環return a.exec();}
> 代碼解釋:
> - ? `#include <opencv2/opencv.hpp>`:包含了使用OpenCV所需的所有核心功能。
> - ? `cv::namedWindow("open cv");`:這是OpenCV的一個函數,它的作用就是創建一個可以顯示圖像的窗口。在我們的測試中,調用這個函數本身就是一種驗證。如果程序能夠編譯鏈接通過,并成功運行到這一行,就說明我們對庫的配置(`.lib`文件鏈接)是正確的。
3.2 編譯項目
????????現在,點擊Qt Creator左下角的“錘子”圖標(或按`Ctrl+B`)來編譯項目。如果前面的`.pro`文件配置無誤,編譯過程應該會順利通過,在輸出欄看到綠色的“編譯完成”信息。
????????編譯成功在這一步意義重大:
????????(1)頭文件找到了:`#include <opencv2/opencv.hpp>`沒有報錯,說明`INCLUDEPATH`配置正確。
????????(2)庫函數鏈接成功了:編譯鏈接階段沒有報`undefined reference to cv::namedWindow`之類的錯誤,說明`LIBS`配置正確,鏈接器成功在`.lib`文件中找到了函數的聲明。
四、第四步:臨門一腳 - 運行與問題排查
????????編譯成功只代表“藍圖”沒問題,但程序能否順利“運行”是另一回事。點擊綠色的“運行”按鈕(或按`Ctrl+R`),下面運行成功的界面:
????????但是您有**極大概率**會遇到程序閃退,或者看到一個Windows系統彈窗,提示“無法啟動此程序,因為計算機中丟失 opencv_world320d.dll”。
????????恭喜您,遇到了新手最常見,也是最經典的問題!
4.1 問題根源:編譯時鏈接 vs 運行時加載
????????為什么會這樣?我們需要理解靜態庫(`.lib`)和動態庫(`.dll`)的區別:
????????-? ?編譯時:編譯器通過`.lib`文件(我們的“地址簿”)知道了`cv::namedWindow`等函數是真實存在的,并記錄下它們位于哪個DLL中。因此編譯能夠成功。
????????-? ?運行時:當您的`testqt.exe`程序開始執行時,操作系統(Windows)的加載器會嘗試去加載該程序所依賴的所有`.dll`文件。它會按照一定的順序搜索這些文件,默認的搜索路徑包括:**1. 程序所在目錄**;2. 系統目錄(System32等);3. `PATH`環境變量中指定的目錄。
????????我們的`opencv_world320d.dll`文件安安穩穩地躺在`D:/MyProjects/3rdparty/opencv/bin`目錄下,而我們生成的`testqt.exe`在另一個單獨的`build-testqt-Desktop.../debug`構建目錄里。操作系統加載器在默認搜索路徑中找不到所需的DLL,于是程序啟動失敗。
4.2 解決方案
????????知道了原因,解決辦法就清晰了:我們必須讓操作系統在運行時能找到我們的DLL文件。這里提供三種由淺入深、從“臨時工”到“正規軍”的解決方案。
4.2.1 方案一:簡單粗暴法 - 手動復制DLL
????????最直觀的方法,就是缺啥補啥。
????????(1)找到您的項目構建目錄,例如`build-testqt-Desktop_Qt_5_15_2_MinGW_64_bit-Debug/debug`。
????????(2)進入我們之前準備的`D:/MyProjects/3rdparty/opencv/bin`目錄。
????????(3)將`opencv_world320d.dll`復制到上述的`debug`文件夾中(與`testqt.exe`文件放在一起)。
????????(4)如果是Release模式,則將`opencv_world320.dll`復制到`release`文件夾中。
再次運行程序,現在它應該可以正常啟動了!您會看到兩個窗口:一個是Qt的空白主窗口,另一個則是一個標題為“open cv”的OpenCV窗口。
????????-? ?優點:立竿見影,易于理解。
????????-? ?缺點:非常繁瑣。每次“Clean”項目后,構建目錄被清空,您都需要重新手動復制一次。不專業,且容易遺忘。
4.2.2 方案二:Qt Creator的優雅之道 - 配置運行環境
????????既然問題出在“工作目錄”,我們可以在Qt Creator中直接為我們的程序指定一個“聰明”的工作目錄。
????????(1)點擊Qt Creator左側的`Projects`圖標,進入項目配置模式。
????????(2)確保當前選中的是您的構建套件(Kit),在`Build & Run`下選擇`Run`標簽頁。
????????(3)找到`Run`設置中的`Working directory`字段。
????????(4)點擊`Browse...`,將其路徑設置為我們存放DLL的目錄:`D:/MyProjects/3rdparty/opencv/bin`。
????????再次運行,程序也能成功啟動。
????????-? ?優點:一次配置,永久生效(在Qt Creator內部)。無需手動復制文件,項目更整潔。
????????-? ?缺點:此設置僅在Qt Creator內部通過“運行”按鈕啟動時有效。如果您直接去`build`目錄雙擊`.exe`文件,它依然會因為找不到DLL而無法運行。這對于最終發布程序是不夠的。
4.2.3 方案三:終極方案 - 編寫構建后腳本(推薦)
????????這是最專業、最一勞永逸的方法。我們通過修改`.pro`文件,讓`qmake`在每次成功編譯鏈接之后,自動執行一個復制命令,將所需的DLL文件拷貝到可執行文件的旁邊。
????????在`.pro`文件末尾添加以下代碼:
# ===================================================================# Post-build step: Copy DLLs# ===================================================================# 自定義一個函數,用于拷貝文件defineTest(copy_dll) {# $$1: source file, $$2: destination directory# QMAKE_POST_LINK 是一個特殊變量,它會在鏈接步驟后執行命令# 使用$$shell_path將路徑中的'/'轉換為'\'以兼容windows的copy命令QMAKE_POST_LINK += $$quote(cmd /c copy /y $$shell_path($$1) $$shell_path($$2))return(true)}# 獲取DLL的源目錄和目標目錄DLL_SOURCE_DIR = $$PWD/../3rdparty/opencv/bin# $$OUT_PWD是qmake變量,指向構建輸出目錄(debug或release)DEST_DIR = $$OUT_PWD# 根據構建模式拷貝對應的DLLCONFIG(debug, debug|release) {copy_dll($$DLL_SOURCE_DIR/opencv_world320d.dll, $$DEST_DIR)} else {copy_dll($$DLL_SOURCE_DIR/opencv_world320.dll, $$DEST_DIR)}
????????> 注意:如果您的Qt版本或環境配置不同,`cmd /c copy`可能需要調整。一個更跨平臺的做法是使用`$$QMAKE_COPY`。為了簡潔易懂,此處使用Windows原生的`copy`命令作為示例。
????????修改后,再次`Run qmake`,然后重新編譯您的項目。編譯完成后,去`build/.../debug`目錄查看,您會發現`opencv_world320d.dll`已經自動出現在那里了!
????????-? ?優點:完全自動化,一勞永逸。無論是從Qt Creator運行,還是直接雙擊exe,或者將`build`目錄打包發給別人,都能完美運行。這是軟件發布的標準做法。
????????-? ?缺點:`.pro`文件配置稍微復雜一點,但一次配置,終身受益。
總結
? ? ? ? 通過以上四個步驟,您已經成功地將強大的OpenCV庫“嫁接”到了您的`testqt`項目中,并掌握了從配置、編碼到部署的全流程。讓我們回顧一下成功的關鍵:
? ? ? ? (1)精心準備:建立清晰的、源碼與依賴分離的目錄結構(`testqt`與`3rdparty`),是項目清晰、可移植的基石。
? ? ? ? (2)精確制導:通過手動編輯`.pro`文件,使用`$$PWD/..`相對路徑和`CONFIG`條件編譯,精確地告訴編譯器頭文件和庫文件的位置,并區分Debug/Release。
????????(3)對癥下藥:深刻理解DLL的運行時加載機制,從而選擇最適合的方案(推薦自動拷貝DLL的構建后腳本)來解決“找不到DLL”的經典問題。
????????這個流程不僅適用于OpenCV,它幾乎適用于任何您想在Qt中使用的第三方C++庫。掌握了這套方法,就等于打通了Qt與其他無數優秀C++生態庫連接的“任督二脈”。
看到這里了還不給博主點一個:
?? 點贊
??收藏
?? 關注
!
💛 💙 💜 ?? 💚💓 💗 💕 💞 💘 💖
再次感謝大家的支持!
你們的點贊就是博主更新最大的動力!