使用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的開發、維護和推廣工作。