OpenCV 4.12.0
開源計算機視覺
載入中...
搜尋中...
無匹配項
如何在“Microsoft Visual Studio”中構建使用 OpenCV 的應用程式

上一個教程: Windows 中的安裝
下一個教程: Image Watch:在 Visual Studio 偵錯程式中檢視記憶體中的影像

原始作者Bernát Gábor
相容性OpenCV >= 3.0
警告
本教程可能包含過時的資訊。

我在這裡描述的所有內容都適用於 OpenCV 的 C\C++ 介面。我假設您已經閱讀併成功完成了 Windows 中的安裝 教程。因此,在您繼續進行任何操作之前,請確保您有一個 OpenCV 目錄,其中包含 OpenCV 標頭檔案和二進位制檔案,並且您已按照此處描述設定了環境變數 設定 OpenCV 環境變數並將其新增到系統路徑

我們分發的 OpenCV 庫在 Microsoft Windows 作業系統上採用動態連結庫 (DLL) 形式。 它們的優點是庫的所有內容僅在執行時按需載入,並且無數程式可以使用同一庫檔案。 這意味著如果您有十個應用程式使用 OpenCV 庫,則無需為每個應用程式都準備一個版本。 當然,您需要在要執行應用程式的所有系統上都擁有 OpenCV 的 dll

另一種方法是使用具有 lib 副檔名的靜態庫。 您可以透過使用我們的原始檔來構建它們,如 Windows 中的安裝 教程中所述。 當您使用此方法時,庫將內建到您的 exe 檔案中。 因此,使用者沒有機會出於某種原因刪除它們。 缺點是您的應用程式會更大,並且在啟動期間載入它會花費更多時間。

要使用 OpenCV 構建應用程式,您需要做兩件事

  • 告訴 編譯器 OpenCV 庫的樣子。 您可以透過顯示它標頭檔案來做到這一點。
  • 告訴 連結器從哪裡獲取 OpenCV 的函式或資料結構(當需要它們時)。

    如果您使用 lib 系統,則必須設定庫檔案所在的路徑,並指定在其中查詢哪個庫。 在構建過程中,連結器將查詢這些庫,並將所有 已使用 函式和資料結構的定義和實現新增到可執行檔案中。

    如果您使用 DLL 系統,則必須再次指定所有這些,但是現在出於不同的原因。 這是一個 Microsoft OS 特有的東西。 似乎連結器需要知道在執行時在 DLL 中的什麼位置搜尋資料結構或函式。 此資訊儲存在 lib 檔案中。 然而,它們不是靜態庫。 它們是所謂的匯入庫。 這就是為什麼當您在 Windows 中製作一些 DLL 時,您最終也會得到一些 lib 擴充套件庫的原因。 好處是在執行時只需要 DLL

要將所有這些資訊傳遞給 Visual Studio IDE,您可以全域性進行(因此您未來的所有專案都將獲得此資訊)或本地進行(因此僅適用於您當前的專案)。 全域性方法的優點是您只需要做一次; 但是,一直用所有這些資訊來堆積您的專案可能是不可取的。 如果是全域性方法,您如何執行取決於您使用的 Microsoft Visual Studio。 有 2008 和以前的版本 以及 2010 版本 的執行方式。 在本教程的全域性部分中,我將展示主要區別是什麼。

Visual Studio 中專案的基礎項是解決方案。 一個解決方案可以包含多個專案。 專案是應用程式的構建塊。 每個專案都將實現某些功能,並且您將有一個主專案,您可以在其中將這個專案難題拼湊在一起。 對於許多簡單的應用程式(例如許多教程),您不需要將應用程式分解為模組。 在這些情況下,您的主專案將是唯一存在的專案。 現在,透過轉到“檔案”–>“新建”–>“專案”選單選擇,在 Visual Studio 中建立一個新解決方案。 選擇 Win32 控制檯應用程式 作為型別。 輸入其名稱並選擇建立它的路徑。 然後在即將出現的對話方塊中,確保建立一個空專案。

本地方法

每個專案都與其他專案分開構建。 因此,每個專案都有自己的規則包。 在此規則包中儲存了 IDE 需要知道的所有資訊才能構建您的專案。 對於任何應用程式,至少有兩種構建模式:ReleaseDebugDebug 具有許多功能,這些功能的存在是為了您可以更輕鬆地在應用程式中查詢和解決錯誤。 相比之下,Release 是一個最佳化版本,其目標是使應用程式執行得儘可能快或儘可能小。 您可能會發現這些模式還需要在構建期間使用不同的規則。 因此,每種構建模式都存在不同的規則包。 這些規則包在 IDE 中稱為專案屬性,您可以透過使用屬性管理器來檢視和修改它們。 您可以透過“檢視”–>“屬性頁”來調出它(對於 Visual Studio 2013 及更高版本,請轉到“檢視”–>“其他視窗”–>“屬性管理器”)。 展開它,您可以看到現有的規則包(稱為屬性表)。

這些屬性表中真正有用的東西是,您可以一次建立一個規則包,以後只需將其新增到您的新專案中即可。 建立一次並在以後重用它。 我們想要建立一個新的 屬性表,其中將包含編譯器和連結器需要知道的所有規則。 當然,我們將需要一個單獨的 Debug 和 Release 版本。 從 Debug 版本開始,如下圖所示

例如,使用 OpenCV_Debug 名稱。 然後透過選擇工作表,右鍵單擊 ->“屬性”。 在下面,我將展示如何在本地設定 OpenCV 規則,因為我認為用我不使用的自定義規則來汙染專案是不必要的。 轉到 C++ 組的“常規”條目,然後在“附加包含目錄”下新增 OpenCV include 的路徑。 如果您沒有“C/C++”組,則應向專案新增任何 .c/.cpp 檔案。

$(OPENCV_DIR)\..\..\include

當新增第三方庫設定時,通常最好利用環境變數背後的強大功能。 OpenCV 庫的完整位置可能會在每個系統上發生變化。 此外,您甚至可能出於某種原因最終移動安裝目錄。 如果您在屬性表中提供顯式路徑,則當您將其傳遞給具有不同 OpenCV 安裝路徑的其他人時,您的專案將最終無法正常工作。 此外,修復此問題需要手動修改每個顯式路徑。 一個更優雅的解決方案是使用環境變數。 您放在以美元符號開頭的括號內的任何內容將在執行時替換為當前環境變數值。 這就發揮了我們在之前的教程 設定 OpenCV 環境變數並將其新增到系統路徑 中已經完成的環境變數設定。

接下來,轉到“連結器”–>“常規”,然後在“附加庫目錄”下新增 libs 目錄

$(OPENCV_DIR)\lib

然後,您需要指定連結器應在其中查詢的庫。 為此,請轉到“連結器”–>“輸入”,然後在“附加依賴項”條目下新增要使用的所有模組的名稱

庫的名稱如下

opencv_(模組名稱)(您使用的庫的版本號)d.lib

最新版本的完整列表將包含

opencv_calib3d300d.lib
opencv_core300d.lib
opencv_features2d300d.lib
opencv_flann300d.lib
opencv_highgui300d.lib
opencv_imgcodecs300d.lib
opencv_imgproc300d.lib
opencv_ml300d.lib
opencv_objdetect300d.lib
opencv_photo300d.lib
opencv_shape300d.lib
opencv_stitching300d.lib
opencv_superres300d.lib
opencv_ts300d.lib
opencv_video300d.lib
opencv_videoio300d.lib
opencv_videostab300d.lib

或者,您的 OpenCV 下載可能已構建為一個大的 .lib 檔案。 透過檢視 OpenCV\build\architecture\vc14\lib 進行檢查。 在這種情況下,您要新增的全部內容是,對於 3.3.0 版本

opencv_world330.lib

末尾的字母 d 只是表示這些是除錯所需的庫。 現在單擊“確定”儲存,並在 Release 規則部分內的新屬性中執行相同的操作。 確保省略庫名稱中的 d 字母,並使用它們上方的儲存圖示儲存屬性表。

您可以在專案的目錄中找到您的屬性表。 此時,最好將它們備份到一些特殊目錄中,以便將來在您建立 OpenCV 專案時始終可以隨時使用它們。 請注意,對於 Visual Studio 2010,副檔名為 props,而對於 2008,則為 vsprops

下次當您建立一個新的 OpenCV 專案時,只需使用“屬性管理器”中的“新增現有屬性表...”選單項即可輕鬆新增 OpenCV 構建規則。

全域性方法

如果您覺得為每個專案新增屬性頁面太麻煩,您也可以將此規則新增到“全域性屬性頁面”。 但是,這僅適用於其他包含目錄和庫目錄。 您仍然需要手動指定要使用的庫的名稱,例如:使用屬性頁面。

在 Visual Studio 2008 中,您可以在以下位置找到它:“工具”–>“選項”–>“專案和解決方案”–>“VC++ 目錄”。

在 Visual Studio 2010 中,這已移至全域性屬性表,該屬性表會自動新增到您建立的每個專案中

該過程與本地方法的情況相同。 只需使用環境變數 OPENCV_DIR 新增包含目錄即可。

測試一下!

現在嘗試一下,下載我們的小測試 原始碼 或從 OpenCV 源的示例程式碼資料夾中獲取它。 將其新增到您的專案並構建它。 這是它的內容

#include <opencv2/core.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
if( argc != 2)
{
cout <<" 用法: " << argv[0] << " ImageToLoadAndDisplay" << endl;
return -1;
}
Mat image;
image = imread(argv[1], IMREAD_COLOR); // 讀取檔案
if( image.empty() ) // 檢查無效輸入
{
cout << "無法開啟或找到影像" << std::endl ;
return -1;
}
namedWindow( "顯示視窗", WINDOW_AUTOSIZE ); // 建立一個用於顯示的視窗。
imshow( "顯示視窗", image ); // 在其中顯示我們的影像。
waitKey(0); // 等待視窗中的按鍵
return 0;
}
n 維密集陣列類
定義 mat.hpp:830
cv::getTickFrequency
double getTickFrequency()
int main(int argc, char *argv[])
定義 highgui_qt.cpp:3
定義 core.hpp:107
STL 名稱空間。

您可以從兩個位置啟動 Visual Studio 構建。 可以從 IDE 內部啟動(鍵盤組合:Control-F5),也可以導航到您的構建目錄並雙擊啟動應用程式。 問題是這兩者相同。 當您從 IDE 啟動它時,其當前工作目錄是專案目錄,否則它是應用程式檔案當前所在的資料夾(因此通常是您的構建目錄)。 此外,如果是從 IDE 啟動,控制檯視窗在完成後不會關閉。 它將等待您的擊鍵。

當您在程式碼中編寫開啟和儲存命令時,記住這一點很重要。 您的資源將相對於您的工作目錄儲存(並在開啟時查詢!!!)。 除非您為 I/O 函式提供完整的顯式路徑作為引數。 在上面的程式碼中,我們開啟 這個 OpenCV 徽標。 在啟動應用程式之前,請確保將影像檔案放在當前工作目錄中。 修改程式碼中的影像檔名,以便在其他影像上進行測試。 執行它,瞧

Visual Studio 中的命令列引數

在我們將來的某些教程中,您會看到程式的主要輸入方法將是透過給出執行時引數。 為此,您可以只啟動一個命令視窗(在開始選單中按 cmd + Enter),導航到您的可執行檔案並使用引數啟動它。 因此,例如,對於我的上一個專案,這將如下所示

D
CD OpenCV\MySolutionName\Release
MySolutionName.exe exampleImage.jpg

在這裡,我首先更改了我的驅動器(如果您的專案不在 OS 本地驅動器上),導航到我的專案並使用示例影像引數啟動它。 雖然在 Linux 系統下使用控制檯視窗是很常見的,但在 Microsoft Windows 上很多人幾乎從未使用過它。 此外,在您測試應用程式時一遍又一遍地新增相同的引數在某種程度上是一項繁瑣的任務。 幸運的是,在 Visual Studio 中有一個選單可以自動完成所有這些操作

在此處指定輸入的名稱,並且當您從 Visual Studio 環境啟動應用程式時,您將自動傳遞引數。 在下一個介紹性教程中,您將看到對上一個原始碼的深入解釋:影像入門