建含人臉識(shí)別的face模塊)
簡(jiǎn)介面向Windows平臺(tái)OpenCV開發(fā)者的完整編譯包基于OpenCV 4.8.0與OpenCV Contrib 4.8.0源碼在Windows 10、VS2022 x64環(huán)境下合并編譯包含全部模塊及依賴庫(kù)重點(diǎn)解決官方預(yù)編譯版不帶Contrib、無(wú)法調(diào)用人臉識(shí)別等擴(kuò)展模塊的問(wèn)題。包內(nèi)共640個(gè)文件以HPP頭文件、H頭文件、DLL動(dòng)態(tài)庫(kù)、LIB導(dǎo)入庫(kù)、CMake配置文件、XML配置文件為主并含少量可執(zhí)行工具與說(shuō)明文檔壓縮包整體77.14MB可直接用于項(xiàng)目配置與二次開發(fā)。該編譯包同時(shí)提供x64平臺(tái)Debug與Release版本適合圖像處理、計(jì)算機(jī)視覺(jué)方向的學(xué)生、研究人員及工程開發(fā)者省去自行下載依賴庫(kù)、配置CMake合并模塊的繁瑣流程。已有904人學(xué)習(xí)瀏覽作者為qq_41697882實(shí)測(cè)可用源碼來(lái)自GitHub開源項(xiàng)目?jī)H限個(gè)人學(xué)習(xí)參考商用或分發(fā)請(qǐng)遵循OpenCV相應(yīng)許可證。 如果你在官網(wǎng)下載了OpenCV 4.8.0 Windows安裝包解壓后想寫人臉識(shí)別Demo大概率會(huì)在#include opencv2/face.hpp那一步開始懷疑人生——頭文件找不到鏈接器報(bào)一堆無(wú)法解析的外部符號(hào)。這不是你不會(huì)配置include/lib路徑而是官方預(yù)編譯包根本沒(méi)把opencv_contrib里的face模塊編進(jìn)去。FaceRecognizer、LBPH、Facemark這套人臉識(shí)別相關(guān)的東西都在contrib倉(cāng)庫(kù)里不自己編譯光靠下載的二進(jìn)制包是永遠(yuǎn)等不來(lái)的。這篇文章就寫我用VS2022在Windows下從源碼編譯OpenCV 4.8.0帶完整人臉識(shí)別模塊的整個(gè)過(guò)程從CMake配置到最終生成可分發(fā)使用的完整安裝包中間穿插我編譯多次之后總結(jié)的踩坑排查經(jīng)驗(yàn)。目標(biāo)是讓你照著走一遍能拿到一個(gè)帶opencv_face、且集成到新項(xiàng)目不會(huì)報(bào)一堆鏈接錯(cuò)誤的完整包。適合需要用C調(diào)用LBPH/Facemark、或者不想在別人的預(yù)編譯包里翻來(lái)翻去找模塊的人。1. 為什么官方安裝包滿足不了人臉識(shí)別需求要理解這件事先搞清楚OpenCV的源碼結(jié)構(gòu)。OpenCV在GitHub上分兩個(gè)倉(cāng)庫(kù)opencv主倉(cāng)庫(kù)和opencv_contrib擴(kuò)展倉(cāng)庫(kù)。官方Windows安裝包只編譯主倉(cāng)庫(kù)里的模塊opencv_contrib里的模塊一個(gè)都不帶。人臉識(shí)別相關(guān)的face模塊恰好就躺在contrib里。這是個(gè)很常見的信息差很多新手在官網(wǎng)下包、解壓、配置環(huán)境一氣呵成最后卡在找不到face.hpp上。那官方包能做什么圖像讀寫、濾波、幾何變換、直方圖、輪廓、dnn深度學(xué)習(xí)推理、級(jí)聯(lián)分類器人臉檢測(cè)Haar/LBP這些主倉(cāng)庫(kù)功能都有。但以下場(chǎng)景必須自己編contrib需求場(chǎng)景官方預(yù)編譯包需要自己編contrib圖像基礎(chǔ)處理/dnn推理有不需要LBPH/EigenFaces/FisherFaces傳統(tǒng)人臉識(shí)別沒(méi)有face模塊Facemark人臉關(guān)鍵點(diǎn)檢測(cè)沒(méi)有face模塊SIFT/SURF等非free特征沒(méi)有xfeatures2d模塊 NONFREE開關(guān)順便糾正一個(gè)誤區(qū)網(wǎng)上不少教程把OpenCV人臉識(shí)別描述得很玄動(dòng)不動(dòng)就要GPU、要CUDA、要dlib。實(shí)際編譯帶人臉識(shí)別模塊的OpenCV完全不需要這些CUDA是深度學(xué)習(xí)推理加速用的傳統(tǒng)人臉識(shí)別和Facemark都是純CPU代碼。你只需要VS2022和CMake門檻比想象中低很多。自己編譯除了能拿到face模塊還有兩個(gè)實(shí)實(shí)在在的好處。第一可以打開BUILD_opencv_world選項(xiàng)把幾十個(gè)模塊合并成一個(gè)opencv_world480.dll集成和分發(fā)時(shí)不用面對(duì)一堆散落的DLL。第二模塊可以按需裁剪不需要的模塊直接關(guān)掉編譯時(shí)間、安裝包體積都能壓下來(lái)。官方預(yù)編譯包是一個(gè)固定組合這些定制能力都給不了你。2. 編譯前準(zhǔn)備版本選型與工具鏈檢查編譯前先把工具鏈備齊省得中途停下來(lái)補(bǔ)環(huán)境。Visual Studio 2022是Windows下OpenCV官方支持的編譯器對(duì)應(yīng)工具集是v143接口標(biāo)記通常用vc17來(lái)表示。安裝時(shí)記得勾選“使用C的桌面開發(fā)”工作負(fù)載純裝一個(gè)VS殼子不夠必須把MSVC編譯器和Windows SDK裝上。這一步很多人跳過(guò)Configure階段CMAKE_CXX_COMPILER找不到整個(gè)流程就卡死了。CMake方面OpenCV 4.8.0要求CMake 3.24以上直接下載最新的3.x版本就行建議用cmake-gui圖形界面配置項(xiàng)多GUI里刷新和觀察開關(guān)狀態(tài)比命令行直觀得多。裝好后記得把cmake加入系統(tǒng)PATH順手驗(yàn)證一下cmake --version。源碼包要下兩個(gè)opencv-4.8.0.zip和opencv_contrib-4.8.0.zip。這兩者的版本號(hào)必須嚴(yán)格一致4.8.0配4.8.0不能一個(gè)用tag一個(gè)用master分支。版本錯(cuò)位是配置失敗的重災(zāi)區(qū)后面我會(huì)單獨(dú)講。解壓路徑遵守一條鐵律純英文、無(wú)空格、不要中文。我最開始圖省事放在帶中文的目錄下編譯時(shí)冒出一堆warning C4819字符編碼警告排查起來(lái)非常費(fèi)時(shí)間。如果你還想要Python綁定編譯出cv2那就提前裝好64位的Python 3.x并在Path里能直接訪問(wèn)到python.exe。CMake配置時(shí)會(huì)把Python版本、頭文件路徑、庫(kù)路徑自動(dòng)抓取出來(lái)。不需要Python綁定的可以直接忽略不影響face模塊。最后是磁盤和編譯時(shí)間的心理預(yù)期。build目錄建議預(yù)留15GB以上空間源碼解壓占2GB左右install安裝包雖然只有幾百M(fèi)B但編譯中間產(chǎn)物很大。內(nèi)存8GB以上比較穩(wěn)Release模式全量編譯大約30到50分鐘機(jī)器差一點(diǎn)的上小時(shí)也正常選一個(gè)能一兩個(gè)小時(shí)不理電腦的時(shí)間段開始編比較合適。3. CMake配置全過(guò)程直接把工程生成到VS2022里3.1 目錄規(guī)劃我習(xí)慣在同一級(jí)目錄下放源碼和構(gòu)建產(chǎn)物D:/opencv/opencv-4.8.0 源碼主倉(cāng)庫(kù) D:/opencv/opencv_contrib-4.8.0 源碼擴(kuò)展倉(cāng)庫(kù) D:/opencv/build-opencv-4.8.0 build目錄CMake生成的VS工程 D:/opencv/install-opencv-4.8.0 最終安裝目錄build目錄不能放在源碼目錄里面OpenCV明確不支持in-source build放在外面以后想刪掉重新配置也干凈。3.2 cmake-gui關(guān)鍵配置項(xiàng)打開cmake-gui第一行Source code填OpenCV主倉(cāng)庫(kù)源碼路徑第二行build填build目錄路徑。點(diǎn)Configure彈出的生成器選擇Visual Studio 17 2022平臺(tái)選x64Finish后開始第一次配置。第一次Configure完成后找到OPENCV_EXTRA_MODULES_PATH這一項(xiàng)填上opencv_contrib-4.8.0/modules路徑重新Configure。這時(shí)候千萬(wàn)盯一下候選項(xiàng)列表里會(huì)冒出一整批BUILD_opencv_xxx開關(guān)其中必須有BUILD_opencv_face且打鉤。有些版本或操作路徑不對(duì)時(shí)BUILD_opencv_face可能會(huì)默認(rèn)是OFF或者干脆不顯示前者手動(dòng)勾上后者說(shuō)明modules路徑配錯(cuò)了回頭查。我把常用的幾個(gè)候選項(xiàng)按使用需求整理了一下BUILD_opencv_worldON強(qiáng)烈建議。所有模塊合并成一個(gè)opencv_world480.dll鏈接時(shí)只需要opencv_world480.lib分發(fā)時(shí)拷貝一個(gè)DLL就行。缺點(diǎn)只是編譯時(shí)間略增利遠(yuǎn)大于弊。BUILD_EXAMPLESON新手建議開編完可以跑自帶的示例驗(yàn)證人臉識(shí)別效果。BUILD_TESTS / INSTALL_TESTS一般OFF編譯測(cè)試代碼很費(fèi)時(shí)間日常用不到。BUILD_opencv_python3需要Python綁定就ON會(huì)額外編譯pybind11相關(guān)代碼。OPENCV_ENABLE_NONFREE如果你還想順手用SIFT/SURF這類專利算法可以O(shè)N。人臉識(shí)別本身不依賴這個(gè)開關(guān)。WITH_MSMF、WITH_FFMPEGWindows下視頻讀寫后端默認(rèn)ON就行。CMAKE_INSTALL_PREFIX默認(rèn)是build/install我習(xí)慣手動(dòng)改成D:/opencv/install-opencv-4.8.0這樣最終產(chǎn)物固定放一個(gè)目錄方便備份和分發(fā)。配置過(guò)程中CMake會(huì)從網(wǎng)上拉取一些三方依賴包比如IPPICV、FFmpeg組件。網(wǎng)絡(luò)不穩(wěn)時(shí)這里最容易掛具體怎么救在第五部分講。拉取結(jié)束后CMake日志里看到“Configuring done”界面上的紅色條目基本消失就可以點(diǎn)Generate生成VS2022工程了。生成完成后build目錄里會(huì)有一個(gè)OpenCV.sln。3.3 配置完成前怎么判斷有沒(méi)有出問(wèn)題別急著生成先確認(rèn)兩件事。第一在cmake-gui搜索框輸入face能找到OPENCV_MODULE_opencv_face_STATUS這類的狀態(tài)變量看它的值是TRUE還是空。如果顯示空或者報(bào)依賴缺失說(shuō)明contrib模塊沒(méi)被識(shí)別。第二看日志區(qū)域有沒(méi)有“XXX will be built”的字樣。OpenCV配置時(shí)會(huì)對(duì)每個(gè)模塊輸出構(gòu)建狀態(tài)如果你選的模塊沒(méi)有被識(shí)別出來(lái)日志里會(huì)有線索。第一次配置出現(xiàn)大量紅色條目是正常的因?yàn)楹芏嗄K還依賴未配置的路徑先把EXTRA_MODULES_PATH填好再configure一次紅色會(huì)少很多。4. 人臉識(shí)別模塊的編譯要點(diǎn)從face模塊到最終的install產(chǎn)物4.1 face模塊里到底有什么很多人以為帶人臉識(shí)別模塊就是能直接調(diào)用“人臉識(shí)別API”拿到包之后又不知道該用哪些類。這里把face模塊的功能盤一遍。傳統(tǒng)人臉識(shí)別部分最常用的是cv::face::FaceRecognizer具體有三個(gè)實(shí)現(xiàn)LBPHFaceRecognizer、EigenFaceRecognizer、FisherFaceRecognizer。LBPH最實(shí)用對(duì)訓(xùn)練樣本數(shù)量要求不高也不需要外部模型文件采集幾張人臉圖片訓(xùn)練后就能做識(shí)別適合本地小項(xiàng)目。Eigen和Fisher對(duì)光照、姿態(tài)很敏感現(xiàn)在實(shí)際項(xiàng)目里用得少了。關(guān)鍵點(diǎn)檢測(cè)部分是Facemark系列FacemarkKazemi、FacemarkLBF、FacemarkAAM可以根據(jù)訓(xùn)練模型在人臉上標(biāo)出眼睛、鼻子、嘴巴的坐標(biāo)。使用時(shí)要額外下載對(duì)應(yīng)的模型文件例如FacemarkLBF需要lbfmodel.yaml這個(gè)文件不在編譯產(chǎn)物里需要去opencv_contrib的samples目錄或官方發(fā)布頁(yè)面單獨(dú)下載。還要區(qū)分一個(gè)概念OpenCV里的級(jí)聯(lián)分類器人臉檢測(cè)Haar/LBP、以及深度學(xué)習(xí)人臉檢測(cè)模型YuNet的FaceDetectorYN這些在主倉(cāng)庫(kù)的objdetect和dnn模塊里官方包就有不需要自己編譯contrib。只有傳統(tǒng)人臉識(shí)別和Facemark這套在face模塊。搞清楚這個(gè)邊界你就明白為什么要自己編譯也明白編譯包里哪些部分是“額外獲得”的。4.2 VS2022里兩步編譯打開build目錄下的OpenCV.sln先把頂部解決方案配置切換成Release平臺(tái)選x64。第一步右鍵ALL_BUILD項(xiàng)目點(diǎn)生成。這一步會(huì)編譯所有開啟的模塊是耗時(shí)大頭。不用單獨(dú)只編face模塊因?yàn)樗蕾嘽ore、imgproc等基礎(chǔ)模塊CMake會(huì)自動(dòng)處理依賴關(guān)系一刀ALL_BUILD下去最省心。第二步右鍵INSTALL項(xiàng)目點(diǎn)生成。這一步會(huì)把include頭文件、lib庫(kù)文件、dll動(dòng)態(tài)庫(kù)、cmake配置文件、haarcascades等數(shù)據(jù)文件復(fù)制到CMAKE_INSTALL_PREFIX指定的目錄。這時(shí)候install目錄就是一個(gè)可直接分發(fā)使用的“完整包”。如果平時(shí)需要調(diào)試C源碼建議Release編完之后把解決方案配置切到Debug再編一遍ALL_BUILD和INSTALL。Debug和Release的庫(kù)文件用d后綴區(qū)分比如opencv_world480.dll對(duì)應(yīng)Releaseopencv_world480d.dll對(duì)應(yīng)Debug。兩個(gè)都裝進(jìn)install目錄后項(xiàng)目在不同配置下都能鏈接到對(duì)應(yīng)版本。4.3 驗(yàn)證產(chǎn)物是否完整編譯結(jié)束后打開install目錄正常情況下結(jié)構(gòu)類似install/ ├─ include/opencv2/ ├─ lib/ 或 x64/vc17/lib/ ├─ bin/ 或 x64/vc17/bin/ ├─ etc/haarcascades 等 └─ OpenCVConfig.cmake確認(rèn)三點(diǎn)include/opencv2/face.hpp存在bin目錄下有opencv_world480.dll或opencv_face480.dllDebug是帶d后綴lib目錄下有對(duì)應(yīng)的導(dǎo)入庫(kù)文件。三個(gè)都在編譯基本算成功了一半。接下來(lái)是真正的驗(yàn)證——用find_package方式集成到一個(gè)最小項(xiàng)目里。先寫一個(gè)簡(jiǎn)單的CMakeLists.txtcmake_minimum_required(VERSION 3.20) project(FaceCheck) find_package(OpenCV REQUIRED) add_executable(FaceCheck main.cpp) target_link_libraries(FaceCheck ${OpenCV_LIBS})main.cpp里調(diào)用一個(gè)face模塊獨(dú)有的類#include opencv2/opencv.hpp #include opencv2/face.hpp #include cstdio int main() { cv::Ptrcv::face::FaceRecognizer model cv::face::LBPHFaceRecognizer::create(); cv::Ptrcv::face::FacemarkLBF facemark cv::face::FacemarkLBF::create(); std::printf(OpenCV %s, face module ok\n, CV_VERSION); return 0; }cmake配置時(shí)把OpenCV_DIR指向install目錄里面有OpenCVConfig.cmake能順利configure、build、運(yùn)行并輸出“face module ok”說(shuō)明人臉識(shí)別模塊確實(shí)編譯進(jìn)去了鏈接也沒(méi)問(wèn)題。這一步比只看DLL存在更可靠很多坑都是在實(shí)際鏈接時(shí)才會(huì)暴露。5. 編譯過(guò)程中的高頻問(wèn)題與排查鏈路這一部分全是我自己編譯過(guò)程中真實(shí)遇到過(guò)的坎按問(wèn)題現(xiàn)象、原因、排查順序來(lái)講你可以直接照著這個(gè)鏈路查。5.1 第三方依賴包下載失敗現(xiàn)象Configure階段卡在類似“IPPICV: Downloading”的日志上最后報(bào)Download failed要么直接中斷要么生成后編譯到一半缺少頭文件。原因OpenCV配置時(shí)會(huì)自動(dòng)下載一些三方組件最典型的是IPPICVIntel性能原語(yǔ)庫(kù)和FFmpeg對(duì)Windows的預(yù)編譯封裝。網(wǎng)絡(luò)環(huán)境不穩(wěn)或連接GitHub超時(shí)都很容易掛在這里。排查鏈路在CMake日志里找到具體的下載URL復(fù)制到瀏覽器手動(dòng)下載??慈罩纠锏哪繕?biāo)文件名通常是“一串哈希值-原文件名.zip”這種結(jié)構(gòu)這個(gè)文件名要原樣保留。把文件放到OpenCV源碼目錄下的.cache對(duì)應(yīng)子目錄中比如ippicv對(duì)應(yīng).cache/ippicvffmpeg對(duì)應(yīng).cache/ffmpeg。重新ConfigureCMake檢測(cè)到緩存文件存在會(huì)跳過(guò)下載直接使用。關(guān)鍵點(diǎn)在于文件名不能改CMake靠這個(gè)哈希名判斷文件有效性和完整性。手動(dòng)下載后如果校驗(yàn)不過(guò)大概率是文件名或者存放目錄不對(duì)。5.2 opencv_contrib版本不匹配現(xiàn)象Configure過(guò)程報(bào)錯(cuò)提示contrib里的模塊版本和主倉(cāng)庫(kù)不匹配或者編譯時(shí)頭文件里一堆找不到定義的API。原因最常見的是拉了opencv_contrib的master分支而主倉(cāng)庫(kù)用的是4.8.0的tag二者API發(fā)展階段不一致。另外還有可能是opencv_contrib解壓目錄設(shè)置錯(cuò)了把整個(gè)倉(cāng)庫(kù)路徑當(dāng)成modules路徑填進(jìn)去了。排查鏈路核對(duì)兩個(gè)zip包的版本號(hào)確保都是4.8.0。檢查OPENCV_EXTRA_MODULES_PATH它的值必須是opencv_contrib-4.8.0/modules這個(gè)子目錄而不是opencv_contrib-4.8.0本身。如果之前配過(guò)master版本把build目錄清空重新Configure一次別在舊緩存上反復(fù)改舊CMakeCache.txt里殘留的配置會(huì)影響新版本判斷。5.3 編譯過(guò)程編譯器崩潰或C4819警告現(xiàn)象編譯到一半cl.exe進(jìn)程崩潰VS提示堆空間不足或者日志里刷大量warning C4819。原因C4819多半是源碼路徑或系統(tǒng)區(qū)域設(shè)置導(dǎo)致的編碼換算問(wèn)題中文路徑是最常見觸發(fā)源。編譯器崩潰則和物理內(nèi)存、殺毒軟件實(shí)時(shí)掃描、編譯并行度有關(guān)。對(duì)策確認(rèn)源碼和build路徑無(wú)中文、無(wú)空格install目錄也一樣。關(guān)閉殺毒軟件的實(shí)時(shí)防護(hù)或者把OpenCV目錄加入白名單。Windows Defender對(duì)海量小文件編譯場(chǎng)景的掃描開銷非常明顯有時(shí)會(huì)直接把編譯進(jìn)程拖垮。如果內(nèi)存不夠在VS的“屬性→C/C→命令行”里加/MP參數(shù)用多核并行編譯可以減少單核壓力但內(nèi)存會(huì)吃得更快內(nèi)存小的話反而更容易崩。更穩(wěn)妥的做法是關(guān)掉BUILD_EXAMPLES和BUILD_TESTS減少同時(shí)編譯的源文件數(shù)量。先編ReleaseRelease優(yōu)化選項(xiàng)默認(rèn)更激進(jìn)但實(shí)際崩潰率比Debug低Debug調(diào)試信息會(huì)讓編譯器內(nèi)存峰值更高。5.4 編完后集成到新項(xiàng)目的四個(gè)常見坑拿到install包只是起點(diǎn)把它接進(jìn)自己的項(xiàng)目也有不少細(xì)節(jié)。我見過(guò)太多人這一步卡住把問(wèn)題怪在編譯頭上。運(yùn)行時(shí)找不到DLL程序啟動(dòng)報(bào)“由于找不到opencv_world480.dll無(wú)法繼續(xù)執(zhí)行代碼”。解法是把install/bin目錄加入系統(tǒng)環(huán)境變量PATH或者把DLL拷貝到exe同目錄。前者一勞永逸后者適合單一程序分發(fā)。Debug和Release混用Release包鏈接到Debug項(xiàng)目或者反過(guò)來(lái)編譯器會(huì)報(bào)“無(wú)法解析的外部符號(hào)”或者_(dá)ITERATOR_DEBUG_LEVEL不匹配。原則是Debug項(xiàng)目配帶d后綴的庫(kù)Release項(xiàng)目配不帶d的庫(kù)。find_package找不到OpenCV多半是OpenCV_DIR沒(méi)有指向install目錄或者指向了build目錄。install目錄下的OpenCVConfig.cmake攜帶的是安裝后的路徑信息用它最穩(wěn)。靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)分不清默認(rèn)BUILD_SHARED_LIBSON是動(dòng)態(tài)庫(kù)鏈接時(shí)需要DLL跟隨運(yùn)行。想要靜態(tài)鏈接就把BUILD_SHARED_LIBSOFF重新編但靜態(tài)庫(kù)部署時(shí)體積大、鏈接依賴復(fù)雜新手不建議輕易換先用默認(rèn)動(dòng)態(tài)庫(kù)跑通整個(gè)流程更重要。最后說(shuō)一點(diǎn)個(gè)人習(xí)慣。我每次編譯完會(huì)把install目錄整個(gè)壓縮成opencv-4.8.0-vc17-x64.zip文件名上標(biāo)注好版本和工具鏈存一份在本地。以后換電腦、新建項(xiàng)目直接解壓這個(gè)包配置好OpenCV_DIR就能用不用每次都從頭編譯。這個(gè)包可復(fù)用性很高團(tuán)隊(duì)內(nèi)部同傳一份大家環(huán)境就統(tǒng)一了。如果你只是做人臉識(shí)別入門LBPH這套老牌算法配上編譯好的完整包已經(jīng)足夠應(yīng)付大部分本地識(shí)別場(chǎng)景先把這條路跑通再考慮深度學(xué)習(xí)模型的性能調(diào)優(yōu)。本文還有配套的精品資源點(diǎn)擊獲取