本文作者:于仕琪(OpenCV團(tuán)隊(duì))
OpenCV 4.x中提供了強(qiáng)大的統(tǒng)一向量指令(universal intrinsics),使用這些指令可以方便地為算法提速。所有的計(jì)算密集型任務(wù)皆可使用這套指令加速,非計(jì)算機(jī)視覺(jué)算法也可。目前OpenCV的代碼加速實(shí)現(xiàn)基本上都基于這套指令。
前序文章:
使用OpenCV中的universal intrinsics為算法提速 (1)
使用OpenCV中的universal intrinsics為算法提速 (2)
前序文章1介紹了怎么編寫(xiě)C語(yǔ)言代碼使用OpenCV中的universal intrinsics來(lái)加速;文章2介紹了編譯器的選項(xiàng)。
本文使用一個(gè)向量點(diǎn)乘的例子,來(lái)展示universal intrinsics的的提速。
我們有兩個(gè)向量vec1和vec2,將對(duì)應(yīng)元素相乘,然后累加起來(lái)。計(jì)算公式為:
sum=vec1[0]*vec2[0] + vec1[1]*vec2[1]+ ... + vec1[n]*vec2[n].
如果采用純C語(yǔ)言,兩個(gè)行向量的點(diǎn)乘實(shí)現(xiàn)如下(如代碼顯示不完整,可以左右滑動(dòng);或橫屏閱讀)
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,兩個(gè)行向量的點(diǎn)乘實(shí)現(xiàn)如下:
(注意:下面函數(shù)僅為展示原理,未考慮數(shù)組長(zhǎng)度不是16(32或64)字節(jié)倍數(shù)情況)
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開(kāi)發(fā)板,OpenCV4.2.0,CPU型號(hào)為是RK3228H,采用ARM四核64位處理器 ,四核Cortex-A53,最高1.3GHz。
兩個(gè)例子的編譯命令分別如下(注意:皆采用了-O3選項(xiàng)以提速):
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
從兩個(gè)函數(shù)的耗時(shí)可以看出,采用OpenCV的universal intrinsics后耗時(shí)僅為一半,速度翻倍。
兩個(gè)例程的完整源代碼如下。首先是C語(yǔ)言版本的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中國(guó)團(tuán)隊(duì)由深圳市人工智能與機(jī)器人研究院支持,是一個(gè)非營(yíng)利的開(kāi)源團(tuán)隊(duì),致力于OpenCV的開(kāi)發(fā)、維護(hù)和推廣工作。
獲取OpenCV最新動(dòng)態(tài),長(zhǎng)按下方二維碼關(guān)注
本文轉(zhuǎn)載自公眾號(hào): OpenCV團(tuán)隊(duì)
審核編輯 黃昊宇
-
人工智能
+關(guān)注
關(guān)注
1789文章
46663瀏覽量
237098 -
OpenCV
+關(guān)注
關(guān)注
29文章
625瀏覽量
41215
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論