使用OpenCV中的universal intrinsics為演算法提速 (2)
- 2020 年 2 月 21 日
- 筆記
前言:因為新型冠狀病毒導致疫情,最近幾日各種新聞和消息滿天飛。疫情之下不易出行、不宜聚會;宜宅在家、宜閱讀、宜學習、宜寫程式碼。鑒於此,本系列第2篇提前發布。希望大家過一個充實的春節。
OpenCV 4.x中提供了強大的統一向量指令(universal intrinsics),使用這些指令可以方便地為演算法提速。所有的計算密集型任務皆可使用這套指令加速,非電腦視覺演算法也可。目前OpenCV的程式碼加速實現基本上都基於這套指令。
前序文章:使用OpenCV中的universal intrinsics為演算法提速 (1)
前序文章介紹了怎麼編寫C語言程式碼使用OpenCV中的universal intrinsics來加速。只是寫C程式碼還是不夠的,universal intrinsics的使用依賴編譯器的選項。
現在我們來看一段測試程式碼hello.cpp:
(程式碼較寬,建議橫屏閱讀)
#include <stdio.h> #include <opencv2/opencv.hpp> #include <opencv2/core/simd_intrinsics.hpp> using namespace cv; int main(int argc, char ** argv) { #ifdef CV_SIMD printf("CV_SIMD is : " CVAUX_STR(CV_SIMD) "n"); printf("CV_SIMD_WIDTH is : " CVAUX_STR(CV_SIMD_WIDTH) "n"); printf("CV_SIMD128 is : " CVAUX_STR(CV_SIMD128) "n"); printf("CV_SIMD256 is : " CVAUX_STR(CV_SIMD256) "n"); printf("CV_SIMD512 is : " CVAUX_STR(CV_SIMD512) "n"); #else printf("CV_SIMD is NOT definedn"); #endif #ifdef CV_SIMD printf("sizeof(v_uint8) = %dn", (int)sizeof(v_uint8)); printf("sizeof(v_int32) = %dn", (int)sizeof(v_int32)); printf("sizeof(v_float32) = %dn", (int)sizeof(v_float32)); #endif return 0; }
1. X64 CPU+Linux下使用g++編譯:
編譯命令是:
g++ hello.cpp -o hello -I/usr/local/include/opencv4 -lopencv_core
然後運行
./hello
得到結果如下:
CV_SIMD is : 1 CV_SIMD_WIDTH is : 16 CV_SIMD128 is : 1 CV_SIMD256 is : 0 CV_SIMD512 is : 0 sizeof(v_uint8) = 16 sizeof(v_int32) = 16 sizeof(v_float32) = 16
運行上述程式的電腦的CPU是Intel(R)Core(TM) i7-1065G7 CPU。這個CPU是支援AVX512的,但是上述程式碼的結果卻是只支援128位向量計算(16個位元組)。
如果希望支援256位(32個位元組)向量計算,編譯程式時需要使用選項-mavx2。目前大部分Intel/AMD CPU都支援AVX2。編譯命令如下:
g++ hello.cpp -o hello -mavx2 -I/usr/local/include/opencv4 -lopencv_core
然後運行生成的程式,結果如下。可以看出現在向量寬度達到了256位(32個位元組)。
CV_SIMD is : 1 CV_SIMD_WIDTH is : 32 CV_SIMD128 is : 1 CV_SIMD256 is : 1 CV_SIMD512 is : 0 sizeof(v_uint8) = 32 sizeof(v_int32) = 32 sizeof(v_float32) = 32
如果希望支援512位(64個位元組)向量計算,編譯程式時需要使用選項-mavx512f。當然你需要有支援AVX512的CPU;而且版本較低的gcc/g++可能不支援AVX512
g++ hello.cpp -o hello -mavx512ifma -I/usr/local/include/opencv4 -lopencv_core
然後運行生成的程式,結果如下。可以看出現在向量寬度達到了512位(64個位元組)。
CV_SIMD is : 1 CV_SIMD_WIDTH is : 64 CV_SIMD128 is : 1 CV_SIMD256 is : 1 CV_SIMD512 is : 1 sizeof(v_uint8) = 64 sizeof(v_int32) = 64 sizeof(v_float32) = 64
特別注意:AVX512有很多不同的擴展,g++支援的有這些:avx512f, avx512pf, avx512eravx512cd, avx512vl avx512bw, avx512dq, avx512ifma, avx512vbmi。大家可以查閱手冊確定使用哪一個。例如要使用整數乘法,需要avx512ifma。
2. ARM CPU+Linux下使用g++編譯:
本人使用Open AI Lab的EAIDK-310開發板,OpenCV4.2.0,編譯命令是:
g++ hello.cpp -o hello -I/usr/local/include/opencv4 -lopencv_core
然後運行
./hello
得到結果如下:
CV_SIMD is : 1 CV_SIMD_WIDTH is : 16 CV_SIMD128 is : 1 CV_SIMD256 is : 0 CV_SIMD512 is : 0 sizeof(v_uint8) = 16 sizeof(v_int32) = 16 sizeof(v_float32) = 16
可以看出g++編譯器默認支援了SIMD。
如果你希望更具體的指定ARM CPU上的SIMD指令,g++編譯器可以使用選項 -mfpu=neon。其他可選的值還有neon-vpfv4、neon-fp-armv8等。具體由編譯器和CPU型號決定。
3. X64 CPU+Windows下使用Visual Studio編譯:
打開Visual Studio項目屬性頁,選擇「配置屬性」-「程式碼生成」-「啟用增強指令集」,從其中選擇你希望使用的指令集。此處不再贅述。

OpenCV中國團隊由深圳市人工智慧與機器人研究院支援,是一個非營利的開源團隊,致力於OpenCV的開發、維護和推廣工作。