[開發環境紀錄] 使用 NCNN + OpenCV 建置 WebAssembly
在 上一篇 文章中分享了透過別人建置好的 WebAssembly 來進行真假人臉辨識,想說趁此機會順便了解一下 WebAssembly 的開發方式。
由於我是使用 Mac 在訓練深度學習的模型,因此也順理成章的使用 Mac 來進行開發環境的設置,但........... 真沒想到過程異常艱辛,解了一個問題又多出另外一個新的問題,於是只好狠下心來改用 Ubuntu 重頭來過,也因此有了這篇血淚記錄文(執行結果如下圖)。
另外因為牽扯技術過多,本文將不會深入探討各項技術的原理,僅記錄環境的設定過程,對於相關技術有興趣的人,可參閱文末參考網站的連結。
在開始詳細說明之前,先列出最終完成時的開發環境版本:
- Ubuntu : 24.04 ,作業系統。
- Python : 3.12.3,使用 OS 內建版本。
- Cmake : 3.28.3,C++ 編譯器。
- Emscripten : 3.1.64,用來將 C++ 程式編譯成 WebAssembly 用。
- OpenCV: 4.10.0,影像處理套件。
環境設定及建置
安裝 Emscripten
WebAssembly,簡稱 WASM,是一種可以讓 C / C++ / C# 等程式語言所產生出來程式(二進制檔案)透過 JavaScript 來進行互動的一種技術,而 Emscripten 則是協助將 C++ 轉譯成 wasm 的一個 toolchain,簡單的運作原理如下圖所示。
圖片來源 : https://juejin.cn/post/7291856546815361064 |
安裝步驟如下,
- 安裝並啟用 Emscripten,此步驟僅須執行一次。
git clone https://github.com/emscripten-core/emsdk.git cd emsdk ./emsdk install latest ./emsdk activate latest - 設定環境變數,每次啟動一個新的 Console 視窗都必須先執行此命令(因為沒有設定 Path)。
emsdk_env.bat
安裝 OpenCV
OpenCV 用於開發即時的圖像處理、電腦視覺以及圖型識別的程式,但請注意,就是這裡卡超久、超雷,因為我們要建置成 WebAssembly,所以請不要使用一般網路上教學的建置 OpenCV 的步驟,安裝建置步驟如下,
- 下載 Open CV Source Code。
# 安裝更新會使用到的相關套件 sudo apt update && sudo apt install -y cmake g++ wget unzip # 直接下載 github 上的版本 git clone https://github.com/opencv/opencv.git # 下載封存的開發版本(我用的方式) wget -O opencv.zip https://github.com/opencv/opencv/archive/4.x.zip unzip opencv.zip - 很重要、很重要、很重要,建置支援 WebAssembly 版的 OpenCV,這個步驟需要一點時間,完成後會在 Source Code 相同目錄下產生 build_wasm 資料夾,相關參數請參考 Build OpenCV.js 說明。
emcmake python3 ./opencv+4.x/platforms/js/build_js.py build_wasm --build_wasm
- (不需要) 底下這段是原本建置 OpenCV 的指令,請注意,如果要建置支援 WebAssembly 版本,請不要使用此方法,完成後會在 Source Code 相同目錄下產生 build 資料夾。
mkdir -p build cmake ../opencv-4.x cmake --build .
安裝 Ncnn
Ncnn,這個框架是西台灣大神開發的,是一個針對行動平台最佳化的高效能神經網路推理框架,它的核心概念是利用 C++ 程式,讓手機使用 CPU 來進行卷積神經網路(CNN)的推論,其中有一個蠻厲害的人將這個框架成功移植到 WebAssembly 上,讓網頁也能進行神經網路推論。
在他的 程式碼範例 中清楚的說明建置的步驟,但先說結論,Ncnn 框架提供了一個簡單的 opencv 方法的類別庫 simpleocv.h,因此其實不需要安裝 OpenCV 也可以執行範例,理論上造著做應該可以成功建置出一個 WebAssembly,但因為秉持著好奇心的關係,想要試著自己調整看看,於是開了一個新的 C++ 程式,引入了 #include "opencv2/opencv.hpp",接著就開始一連串的錯誤。
PS. 我沒有深入研究作者範例中提供的 ncnn-20230223-webassembly 的差異是什麼,但若你依照本文上述的步驟,請改下載成最新版本 ncnn-20240410-webassembly。
建置範例程式
專案路徑如下參考
UserHome |__ Project |__ Lib | |__ emsdk | |__ ncnn-20240410-webassembly | |__ opencv_setup | |__ build_wasm (手動建置) | |__ opencv-4.x |__ WebAssemblyDemo
為了測試 WebAssembly 的開發流程,我寫了一個簡單的加法程式來進行初步測試(下圖所示),但為了避免範例過於複雜,我另外引入了 OpenCV 和 NCNN 類別庫,這主要是為了測試整體能否順利通過建置,而非進行 OpenCV 和 NCNN 的實際開發。
- 範例程式 main.cpp
#include #include "net.h" // 測試是否可以使用 ncnn #include "opencv2/opencv.hpp" // 測試是否可以使用 OpenCV int main() { printf("預設的 main Method\n"); return 0; } // 故意寫一個 add Method 來測試是否可以被編譯器保留 EM_PORT_API(int) add(int a, int b) { int sum = a + b; printf("The sum of %d and %d is: %d\n", a, b, sum); return sum; } // 故意寫一個不會被編譯器保留的 helloWorld Method void helloWorld() { printf("Hello World\n"); }
- CMakeList.txt
# 設定建置專案所需的最低 CMake 版本 cmake_minimum_required(VERSION 3.10) # 定義專案名稱和版本 project(wasm-demo VERSION 1.0) # 設定建置類型為 release 模式 set(CMAKE_BUILD_TYPE release) # 指定 C++ 標準版本 set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) # 設定 OpenCV 函式庫的路徑,這是為 WebAssembly 建置的版本 set(OpenCV_DIR "~/Project/Lib/opencv_setup/build_wasm") find_package(OpenCV REQUIRED) # 輸出 OpenCV 函式庫的詳細資訊作為狀態訊息。 message(STATUS "OpenCV library: ${OpenCV_INSTALL_PATH}") message(STATUS " version: ${OpenCV_VERSION}") message(STATUS " libraries: ${OpenCV_LIBS}") message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") # 如果需要進行除錯,取消下面這行的註解,讓建置過程在此處失敗。 # message(FATAL_ERROR "DEBUG...") # 設定 ncnn 函式庫的路徑,這是為 WebAssembly 建置的版本 set(ncnn_DIR "~/Project/Lib/ncnn-20240410-webassembly/${WASM_FEATURE}/lib/cmake/ncnn") find_package(ncnn REQUIRED) # 增加需要編譯的 C++ 檔案 add_executable(${PROJECT_NAME} main.cpp) # 指定輸出文件名稱,放置於 "dest" 目錄中,並根據 WASM_FEATURE 命名 set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ../dest/${PROJECT_NAME}-${WASM_FEATURE}) # 鏈結 OpenCV 函式庫 target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS}) # 鏈結 ncnn 函式庫 target_link_libraries(${PROJECT_NAME} ncnn)
- 切到專案路徑後,執行底下指令建置 WebAssembly,底下 -j6 請根據自己的處理器的數量自行調整。
mkdir build && cd build cmake -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DWASM_FEATURE=simd .. make -j6
疑難雜症紀錄
1. cmake 使用 Emscripten.cmake 的 toolchain 建置 OpenCV 引發的錯誤訊息 執行命令
cmake -DCMAKE_TOOLCHAIN_FILE=$EMSDK/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DWASM_FEATURE=simd .. && make -j6
網路上查到 的兩個解決方式
- 我用這個沒用,sudo apt-get install libopencv-dev
- 自行編譯安裝,set(OpenCV_DIR {OpenCVConfig.cmake所在目錄})
2. 上一個問題改用自行編譯處理完後,引發另外一個錯誤。
這個就是我卡住的地方,還有網友也有熱心的提供類似的經驗,但我這個時候還沒能發現是要另外建置 OpenCV WebAssembly 版本 Orz... ,浪費了超多時間滴。
3. cmake 同時使用 OpenCV + Ncnn 時出現底下錯誤
解決方式,原本使用的是 ncnn-20230223-webassembly,改下載成最新版本 ncnn-20240410-webassembly。
4. cmake 使用 Emscripten.cmake 的toolchain建置 OpenCV+ NCNN引發的錯誤訊息
解決方式,原本使用的是 ncnn-20230223-webassembly,改下載成最新版本 ncnn-20240410-webassembly。
本文範例可自行到 Github 下載。
參考網站
Emscripten & WebAssembly
- 快速上手WebAssembly应用开发:Emscripten使用入门
- WebAssembly和Emscripten入门简介
- Emscripten快速入门
- 使用 WebAssembly SIMD 的快速平行應用程式
留言
張貼留言
您好,我是 Lawrence,這裡是我的開發筆記的網誌,如果你對我的文章有任何疑問或者有錯誤的話,歡迎留言讓我知道。