[開發環境紀錄] 使用 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,這裡是我的開發筆記的網誌,如果你對我的文章有任何疑問或者有錯誤的話,歡迎留言讓我知道。