在Windows上采用Cmake + Visual Studio編譯並使用靜態opencv庫並打包發布成裸機可執行程序
環境:Windows 7 64bit
工具
- Cmake-3.11.1
- 確保是64位
- 確保安裝了GUI
- Visual Studio 2015
- 確保是64位
- 確保采用vc14作為編譯器(支持c++11標准部分語法)
原料:OpenCV 3.4.1 & opencv-contrib-3.4.1
- 中文:從官方網站或者Github上下載opencv3.4.1以及opencv-contrib-3.4.1的源碼.
- English: source all code packages from official website of opencv or Github.
- 日本語:公式サイトまたGithubからのOpenCV-3.4.1をソースコードしてください。
操作步驟
-
解壓opencv-3.4.1源碼包,設解碼后根目錄為OPENCV_DIR,解壓opencv-contrib-3.4.1源碼包,設解碼后的根目錄為OPENCV_CONTRIB_DIR;
-
打開Cmake-3.11.1,選擇source code的路徑為OPENCV_DIR/sources,創建靜態庫存放目錄build-static在opencv根目錄下,如圖;
-
點擊configure(配置)按鈕,選擇visual studio 14 2015 Win64,如圖;
-
等待初次configure完成,中間區域內會出現一系列編譯選項,如圖-3所示;
-
更改編譯選項使得編譯為靜態庫而非動態庫:搜索SHARED,在中間區域修改BUILD_SHARED_LIBS的選中狀態為OFF(checkbox未選中狀態),如圖;
-
更改編譯選項使得包含opencv-contrib-3.4.1中的模塊:搜索EXTRA,在中間區域修改OPENCV_EXTRA_MODULES_PATH的Value為opencv-contrib-3.4.1的解壓路徑下的子路徑:OPENCV_CONTRIB_DIR/modules,如圖;
-
(可選)更改編譯選項去掉不太必要編譯的測試應用程序,因為它們體積巨大,耗時過久:搜索BUILD_EXAMPLES,設置狀態為OFF;搜索BUILD_TESTS,設置狀態為OFF;搜索BUILD_PERF_TESTS,設置為OFF,如圖;
-
點擊Configure按鈕開始配置項目,會發現依然存在紅色的編譯選項,表示這些編譯選項在本機上是不支持的(平台限制以及安裝的依賴軟件限制等因素造成的不支持),如圖;
-
檢查最下方的消息框內,如果發現紅色文字,表示存在失敗項目,一般而言是由於配制過程中下載失敗導致,如圖;
-
重新點擊configure,發現依然存在下載失敗導致的配置錯誤,但上次下載失敗的ffmpeg組件下載成功了,這表明,這些只是網絡不穩定導致的下載失敗,多嘗試幾次configure,也許能解決問題,如果實在不行,請自行下載放置於對應的目錄,例如對於contrib下的xfeatures模塊,將對應的vggnet模型文件等下載后放到OPENCV_CONTRIB_DIR/modules/xfeatures/src/, 如圖,具體的下載源地址以及放置路徑請查看cmake編譯結果存放的目錄下的CMakeDownloadLog.txt;
-
再次點擊Configure配置,發現依然存在下載失敗,但已經沒有紅色配置錯誤消息了,點擊Generate按鈕生成visual studio的項目文件,如圖;
-
點擊open project打開visual studio 2015進行opencv的編譯,如圖;
-
設置編譯類型為Release x64,如圖;
-
右鍵點擊BUILD_ALL,選擇生成,如圖;
-
等待編譯結束,但是,一般會發生c++ compiler driver崩潰以及tracker.exe崩潰的情況,這是因為visual studio的分布式編譯器崩潰了導致的,進而,會發現編譯進度條長時間卡死在某處,也不在輸出新的編譯信息,這表明,要清空重新編譯opencv。如圖;
-
強制關閉visual studio,一般需要打開任務管理器,結束進程后,再打開visual studio,將Debug再改成Release(可能是崩潰后導致配置信息丟失),清理項目后再生成,如圖;
-
再次編譯opencv的ALL_BUILD(在編譯過程中確保不要運行其他的程序,尤其是谷歌瀏覽器chrome等占用內存極大的軟件!)得到編譯結果,如圖;
-
注意到有3個模塊因為xfeatures2d的cuda.hpp頭文件找不到而編譯失敗,但實際上,這些文件是存在的,只是不再它所預期的位置,那么需要將這些頭文件拷貝至其所期待的位置,不要氣餒,不要煩躁,開源的樂趣就是自己動手解決一切!這里的cuda.hpp其實是在opencv-contrib-3.4.1中,不在核心源碼中,需要拷貝到stitching模塊中,如圖;
-
再次生成,本次生成vs2015會執行增量編譯,因此不需擔心再耗時長久,得到編譯結果如圖(需要等待至少10分鍾左右);
-
可以看到,編譯全部成功,一共79個模塊,現在需要安裝靜態庫,其實也就是執行拷貝操作,將分散的模塊都整到一個文件夾下,右鍵點擊INSTALL,執行生成,如圖;
-
關閉visual studio以及cmake,自此,opencv編譯完成!!!おめでたい!おめでたい!如圖;
-
需要注意的是:staticlib文件夾下存放的是opencv及其依賴的靜態庫文件,依賴項一共11項,剩下的以opencv_為前綴的模塊都是Opencv自己的模塊,如圖;
-
在bin中,存放着測試應用,還有一個ffmpeg_64模塊的動態組件,這個似乎無論如何都是編譯為動態的,在使用到視頻解碼的時候會用到,需要自行拷貝到自己開發的程序的bin目錄下,否則無法運行!如圖;
-
現在開始創建一個基於靜態opencv庫的靜態發布的應用,創建一個控制台應用程序,vc++目錄配置為install目錄下的include/opencv以及inclue/opencv2、staticlib目錄,如圖;
-
配置項目為Release x64,和編譯opencv一樣,然后創建opencvConfig.h頭文件,加入以下代碼來導入所需的庫文件;
#pragma once
#include <opencv2/opencv.hpp>
#define CV_VERSION_ID CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION)
#define CALC_CV_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#ifdef _DEBUG
#define cvLIB(name) "opencv_" name CV_VERSION_ID "d"
#else
#define cvLIB(name) "opencv_" name CV_VERSION_ID
#endif
// WINDOWS LIBS
#pragma comment(lib, "wsock32")
#pragma comment(lib, "ws2_32")
#pragma comment(lib, "kernel32")
#pragma comment(lib, "user32")
#pragma comment(lib, "gdi32")
#pragma comment(lib, "winspool")
#pragma comment(lib, "comdlg32")
#pragma comment(lib, "advapi32")
#pragma comment(lib, "shell32")
#pragma comment(lib, "ole32")
#pragma comment(lib, "oleaut32")
#pragma comment(lib, "uuid")
#pragma comment(lib, "odbc32")
#pragma comment(lib, "odbccp32")
//opencv3.4.1 requirements
#pragma comment(lib, "IlmImf")
#pragma comment(lib, "ippicvmt")
#pragma comment(lib, "ippiw")
#pragma comment(lib, "ittnotify")
#pragma comment(lib, "libjasper")
#pragma comment(lib, "libjpeg")
#pragma comment(lib, "libpng")
#pragma comment(lib, "libprotobuf")
#pragma comment(lib, "libtiff")
#pragma comment(lib, "libwebp")
#pragma comment(lib, "zlib")
//opencv3.4.1 modules
#pragma comment(lib,cvLIB("aruco"))
#pragma comment(lib,cvLIB("bgsegm"))
#pragma comment(lib,cvLIB("bioinspired"))
#pragma comment(lib,cvLIB("calib3d"))
#pragma comment(lib,cvLIB("ccalib"))
#pragma comment(lib,cvLIB("core"))
#pragma comment(lib,cvLIB("datasets"))
#pragma comment(lib,cvLIB("dpm"))
#pragma comment(lib,cvLIB("face"))
#pragma comment(lib,cvLIB("features2d"))
#pragma comment(lib,cvLIB("flann"))
#pragma comment(lib,cvLIB("fuzzy"))
#pragma comment(lib,cvLIB("hfs"))
#pragma comment(lib,cvLIB("highgui"))
#pragma comment(lib,cvLIB("imgcodecs"))
#pragma comment(lib,cvLIB("imgproc"))
#pragma comment(lib,cvLIB("img_hash"))
#pragma comment(lib,cvLIB("line_descriptor"))
#pragma comment(lib,cvLIB("ml"))
#pragma comment(lib,cvLIB("objdetect"))
#pragma comment(lib,cvLIB("optflow"))
#pragma comment(lib,cvLIB("phase_unwrapping"))
#pragma comment(lib,cvLIB("photo"))
#pragma comment(lib,cvLIB("plot"))
#pragma comment(lib,cvLIB("reg"))
#pragma comment(lib,cvLIB("rgbd"))
#pragma comment(lib,cvLIB("saliency"))
#pragma comment(lib,cvLIB("shape"))
#pragma comment(lib,cvLIB("stereo"))
#pragma comment(lib,cvLIB("stitching"))
#pragma comment(lib,cvLIB("structured_light"))
#pragma comment(lib,cvLIB("superres"))
#pragma comment(lib,cvLIB("surface_matching"))
#pragma comment(lib,cvLIB("tracking"))
#pragma comment(lib,cvLIB("video"))
#pragma comment(lib,cvLIB("videoio"))
#pragma comment(lib,cvLIB("videostab"))
#pragma comment(lib,cvLIB("xfeatures2d"))
#pragma comment(lib,cvLIB("ximgproc"))
#pragma comment(lib,cvLIB("xobjdetect"))
#pragma comment(lib,cvLIB("xphoto"))
其中,windows庫最好一個都不能少,否則如果用到了某些組件依賴於windows內置組件,會鏈接失敗;剩下的庫是opencv依賴庫以及opencv自身模塊了,opencv模塊選擇自己當前應用所依賴的就行;
-
(重要)配置項目屬性,選擇代碼生成為MT類型,這表示編譯時所依賴的公共運行時庫會被直接嵌入到生成的可執行文件中,這確保運行時不依賴其他任何外部代碼,如圖;
-
最后執行生成就能得到靜態的打包在一個獨立的可執行程序中的文件,如圖,可以看到這個文件大小超出尋常!將這個文件拷貝至任何同樣的操作系統平台下都可以直接運行,教程結束!