本文作者:于仕琪(OpenCV團隊)
OpenCV 4.x中提供了強大的統一向量指令(universal intrinsics),使用這些指令可以方便地為算法提速。所有的計算密集型任務皆可使用這套指令加速,非計算機視覺算法也可。目前OpenCV的代碼加速實現基本上都基于這套指令。
前序文章:
使用OpenCV中的universal intrinsics為算法提速 (1)
使用OpenCV中的universal intrinsics為算法提速 (2)
前序文章1介紹了怎么編寫C語言代碼使用OpenCV中的universal intrinsics來加速;文章2介紹了編譯器的選項。
本文使用一個向量點乘的例子,來展示universal intrinsics的的提速。
我們有兩個向量vec1和vec2,將對應元素相乘,然后累加起來。計算公式為:
sum=vec1[0]*vec2[0] + vec1[1]*vec2[1]+ ... + vec1[n]*vec2[n].
如果采用純C語言,兩個行向量的點乘實現如下(如代碼顯示不完整,可以左右滑動;或橫屏閱讀)
float dotproduct_c_float(Mat vec1, Mat vec2)
{
float * pV1 = vec1.ptr(0);
float * pV2 = vec2.ptr(0);
float sum = 0.0f;
for (size_t c = 0; c < vec1.cols; c++)
{
sum += pV1[c] * pV2[c];
}
return sum;
}
如果采用OpenCV的universal intrinsics,兩個行向量的點乘實現如下:
(注意:下面函數僅為展示原理,未考慮數組長度不是16(32或64)字節倍數情況)
float dotproduct_simd_float(Mat vec1, Mat vec2)
{
float * pV1 = vec1.ptr(0);
float * pV2 = vec2.ptr(0);
size_t step = sizeof(v_float32)/sizeof(float);
//向量元素全部初始化為零
v_float32 v_sum = vx_setzero_f32();
for (size_t c = 0; c < vec1.cols; c+=step)
{
v_float32 v1 = vx_load(pV1+c);
v_float32 v2 = vx_load(pV2+c);
//把乘積累加
v_sum += v1 * v2;
}
//把向量里的所有元素求和
float sum = v_reduce_sum(v_sum);
return sum;
}
例程使用OPEN AI LAB的EAIDK-310開發板,OpenCV4.2.0,CPU型號為是RK3228H,采用ARM四核64位處理器 ,四核Cortex-A53,最高1.3GHz。
兩個例子的編譯命令分別如下(注意:皆采用了-O3選項以提速):
g++ dotproduct-c.cpp -o dotproduct-c -O3 -I/usr/local/include/opencv4 -lopencv_core
g++ dotproduct-simd.cpp -o dotproduct-simd -O3 -I/usr/local/include/opencv4 -lopencv_core
從兩個函數的耗時可以看出,采用OpenCV的universal intrinsics后耗時僅為一半,速度翻倍。
兩個例程的完整源代碼如下。首先是C語言版本的dotproduct-c.cpp:
#include
using namespace cv;
float dotproduct_c_float(Mat vec1, Mat vec2)
{
float * pV1 = vec1.ptr(0);
float * pV2 = vec2.ptr(0);
float sum = 0.0f;
for (size_t c = 0; c < vec1.cols; c++)
{
sum += pV1[c] * pV2[c];
}
return sum;
}
int main(int argc, char ** argv)
{
Mat vec1(1, 16*1024*1024, CV_32FC1);
Mat vec2(1, 16*1024*1024, CV_32FC1);
vec1.ptr(0)[2]=3.3f;
vec2.ptr(0)[2]=2.0f;
double t = 0.0;
t = (double)getTickCount();
float sum = dotproduct_c_float(vec1, vec2);
t = ((double)getTickCount() - t) / (double)getTickFrequency() * 1000;
printf("C time = %gms/n", t);
printf("sum=%g/n", sum);
return 0;
}
dotproduct-simd.cpp如下:
#include
#include
#include
using namespace cv;
float dotproduct_simd_float(Mat vec1, Mat vec2)
{
float * pV1 = vec1.ptr(0);
float * pV2 = vec2.ptr(0);
size_t step = sizeof(v_float32)/sizeof(float);
//向量元素全部初始化為零
v_float32 v_sum = vx_setzero_f32();
for (size_t c = 0; c < vec1.cols; c+=step)
{
v_float32 v1 = vx_load(pV1+c);
v_float32 v2 = vx_load(pV2+c);
//把乘積累加
v_sum += v1 * v2;
}
//把向量里的所有元素求和
float sum = v_reduce_sum(v_sum);
return sum;
}
int main(int argc, char ** argv)
{
Mat vec1(1, 16*1024*1024, CV_32FC1);
Mat vec2(1, 16*1024*1024, CV_32FC1);
vec1.ptr(0)[2]=3.3f;
vec2.ptr(0)[2]=2.0f;
double t = 0.0;
t = (double)getTickCount();
float sum = dotproduct_simd_float(vec1, vec2);
t = ((double)getTickCount() - t) / (double)getTickFrequency() * 1000;
printf("SIMD time = %gms/n", t);
printf("sum=%g/n", sum);
return 0;
}
OpenCV中國團隊由深圳市人工智能與機器人研究院支持,是一個非營利的開源團隊,致力于OpenCV的開發、維護和推廣工作。
獲取OpenCV最新動態,長按下方二維碼關注
本文轉載自公眾號: OpenCV團隊
審核編輯 黃昊宇
-
人工智能
+關注
關注
1792文章
47409瀏覽量
238924 -
OpenCV
+關注
關注
31文章
635瀏覽量
41386
發布評論請先 登錄
相關推薦
評論