前言
不知不覺,正兒八經地寫代碼已經有三年多了。OpenCV是我這三年來用的最多的庫,在Visual Studio中配置它的開發環境,算是家常便飯,已經相當熟稔。回想自己初學OpenCV時的經歷,在網上看教程找資料,走了不少彎路。所以我寫下這篇博文,把配置過程中的東西都講清楚,讓讀到的人少走些彎路。在HOW部分,我將敘述如何配置,並盡量使配置過程簡單明了;在WHY部分,我會盡量講清楚為什么這樣配置。
教程開始前,我希望你能清楚集成開發環境(Integrated Development Environment, IDE)和編譯器是兩碼事兒,Visual Studio是IDE,而VC是編譯器。VC是VS的子集。在不嚴謹的情況下,可以把它們當作一回事兒,但一定要清楚你的VS/VC的版本。各版本的VS和VC對應關系如下表(太古老的版本就不列出來了):
IDE | 編譯器 |
---|---|
VS2017 | VC15 |
VS2015 | VC14 |
VS2013 | VC12 |
VS2012 | VC11 |
VS2010 | VC10 |
VS2008 | VC9 |
VS2005 | VC8 |
另外,本文將使用VS2013和OpenCV-3.0為例。其他版本的配置差別不大,可以依葫蘆畫瓢。
HOW
(0) 准備工作
首先在VS中新建一個空的c++工程:
在項目中新增一個.cpp文件,然后寫上一段簡單的測試代碼(讀取一副圖片然后將其顯示出來):
// 一段簡單的測試代碼
#include <opencv2\opencv.hpp>
int main() {
cv::Mat img = cv::imread("E:\\cap.png"); //改成你自己的圖片路徑
cv::imshow("test", img);
cv::waitKey(0);
}
(1) 配置附加包含目錄
對項目【右鍵】-【屬性】
彈出屬性頁,依次點擊【配置屬性】-【C/C++】-【常規】-【附加包含目錄】,在彈出的窗口中把OpenCV的include路徑填進去。本文填寫的是【E:\ENV\opencv-3.0\include】。
注意上方【配置】和【平台】兩個復選框里面的內容。后文將詳細說明。
(2) 配置附加庫目錄
同樣是在項目的屬性頁,依次點擊【配置屬性】-【鏈接器】-【常規】-【附加庫目錄】,在彈出的窗口中把OpenCV的lib路徑填進去。
本文填寫的路徑是【E:\ENV\opencv-3.0\build\x86\vc12\lib】,其中【x86\vc12】代表此庫由VC12編譯生成,32位。如果你需要其他版本的庫,也可以改成對應的路徑。后文將詳細說明。
(3) 配置附加依賴項
依然是在項目的屬性頁,依次點擊【配置屬性】-【鏈接器】-【輸入】-【附加依賴項】,在彈出的窗口中填入【opencv_ts300.lib】和【opencv_world300.lib】。其中300代表OpenCV-3.0,是版本號。后文將詳細說明。
(4) 配置dll
這一部有兩種做法,第一種方法(推薦)是把【E:\ENV\opencv-3.0\build\x86\vc12\bin】目錄下的dll文件【opencv_world300.dll】拷貝一份,放到本項目生成的exe文件所在目錄中,見下圖。如果你沒有Debug這個目錄,那么先把項目生成/運行一遍就有了。
第二種方法(不推薦)是把【E:\ENV\opencv-3.0\build\x86\vc12\bin】加到系統的環境變量,如下圖,在右側兩個【Path】中選擇一個編輯加入路徑就行了。
(5) 測試
至此已完成全部配置工作!按下F5運行一開始准備好的測試代碼,看看效果吧:
成功運行!
(*) 注意
某些教程會教你在【配置屬性】-【VC++目錄】中修改【附加包含目錄】和【附加庫目錄】,如下圖。在這里修改雖然方便,但我不推薦。
WHY
為了弄清楚為什么要這樣配置,我們來看看OpenCV文件夾里都有什么:
- build
- sources
- LICENSE.txt
- README.md.txt
兩個txt文件,分別是許可證和說明,不重要;兩個文件夾,【sources】文件夾中是OpenCV的源代碼,如果僅僅是調用OpenCV庫,那么我們多半用不上這個文件夾里面的東西。【build】文件夾中包括頭文件,和一些現成的庫文件。這些庫文件是由OpenCV官方生成的。(當然你也可以利用CMake自己生成這些庫文件,CMake是一款跨平台的make軟件,【sources】文件夾里面提供了CMake配置文件。我勸大家不要自己用去生成庫,因為實在是太折騰了。)
再來仔細看看【build】文件夾里面的東西:
- etc
- include
- java
- python
- x64
- x86
- LICENSE
- OpenCVConfig.cmake
- OpenCVConfig-version.cmake
【etc】文件夾中是OpenCV某些算法所依賴的數據集;
【include】里面是一堆頭文件,在 步驟(1) 中,我們將此目錄加入了【附加包含目錄】,就是為了使我們測試代碼中的第一行#include <opencv2\opencv.hpp>
生效。#include
是在【包含目錄】中搜索頭文件的,【附加包含目錄】顧名思義,也屬於【包含目錄】;
【java】和【python】文件夾與本文討論的內容無關;
【x86】和【x64】對應32位庫和64位庫。OpenCV-3.1官方沒有提供32位的庫,自然也就沒有【x86】這個文件夾了。如果你需要32位的OpenCV-3.1庫,可以自己去生成,但建議你先去網上找一找,看看第三方組織或個人生成的庫文件中有沒有你想要的。
最后是許可證以及兩個CMake相關的文件,不重要。
在 步驟(2) 中,本文將【E:\ENV\opencv-3.0\build\x86\vc12\lib】加入了【附加庫目錄】,這樣做是在是調用“32位的、由vc12編譯器生成的、動態鏈接庫形式的、OpenCV庫”,注意到引號里用了三個形容詞,它們依次與路徑中的【x86】、【vc12】、【lib】相對應。①【x86】:如果你想調用64位的庫,那么在路徑中寫【x64】就行了(當然啦前提是這個庫存在,前面也說過了,這里不贅述)。如果你不知道該調用32位還是64位的庫,那么請和你自己的程序保持一致,這是最簡單穩妥的做法。②【vc12】:與上一點一樣,如果不知道該調用由哪個編譯器生成的庫,那么就與自己的程序保持一致。這是因為vcxx編譯出來的庫,依賴於一個叫做microsoft visual c++ 20xx redistributable package的東西(簡稱vcxx運行庫),在安裝VS20xx的時候會自動安裝。本文調用vc12版的OpenCV庫,VS版本為2013;如果使用VS2015編寫程序,調用vc12版的OpenCV庫,需安裝vc12運行庫。③【lib】:與該文件夾同級的,還有【bin】和【staticlib】文件夾。【lib】和【bin】提供動態鏈接庫,【staticlib】提供靜態庫(關於靜態庫和動態庫,可以看看這篇文章:C++靜態庫與動態庫 吳秦)。如果你不知道該調用靜態還是動態庫,建議調用動態庫。原因不多說,我自己也沒有徹底弄清楚,就不誤導別人了。
在 步驟(3) 中,本文在【附加依賴項】中填入了【opencv_ts300.lib】和【opencv_world300.lib】。很多教程在這里,針對程序的debug版本和release版本,填入了不同的內容:debug版本會在".lib"前,加上一個字母"d"。這是為了讓程序在debug模式下,調用debug版本的OpenCV庫。我認為,只要你不需要在調試代碼的時候,進入OpenCV庫函數里面一探究竟,就沒必要做這一步,畢竟debug庫速度不及release庫。所以按照本文的配置,無論VS用debug還是release模式,調用的都是release庫。
很多人不清楚debug模式和releas模式本的區別,簡單按字面意思解釋,debug版本用於調試,release版本用於發布。說一些它們的區別:前者會在編譯階段輸出符號文件(.pdb文件),符號文件是調試的必需品;后者則會開啟編譯器的優化項,把一些中間變量優化掉——這就是為什么我們以release模式去調試的時候,很多變量的值都無法查看。
步驟(3) 也能以顯式的方法,寫在代碼里。將下面兩行代碼加在測試代碼開頭,就能代替 步驟(3) 了。
#pragma comment(lib,"E:\\ENV\\opencv-3.0\\build\\x86\\vc12\\lib\\opencv_ts300.lib")
#pragma comment(lib,"E:\\ENV\\opencv-3.0\\build\\x86\\vc12\\lib\\opencv_world300.lib")
在 步驟(4) 中,本文這樣配置,是為了讓項目生成的exe文件在運行時,能夠找到dll。exe在運行時,會在特定的目錄下尋找自己依賴的庫,它本身所在的目錄肯定包含其中,故在第一種方法中,本文將OpenCV的dll拷貝到了exe的同級目錄下;系統高級設置里面,環境變量【path】中的一連串目錄也是exe搜索的范圍,故在第二種方法中,本文將OpenCV的dll文件所在的目錄,加入了環境變量【path】中。某些教程將OpenCV的dll拷貝到了system32這個系統目錄下……雖然這方法行得通,但我覺得毫無優雅可言。
最后,如果你有任何疑問與建議,或是我的文章存在紕漏,歡迎留言交流!
本作品采用知識共享署名-非商業性使用 4.0 國際許可協議進行許可。