我已经开始第一次使用OpenCL了,我正试图在这个站点进行sobel边缘检测这个例子http://www.karlosp.net/blog/2012/05/03/opencl-opencv-sobel-edge-detector/但是当运行时,kernal的gpu数量fps小于15且gpu利用率小于5%可以像openmp那样为gpu运行所有线程,使得利用率降低95%
代码
核心代码
kernel void sobel(global float * A, global float * R,uint width,uint height){
int globalIdx = get_global_id(0);
int globalIdy = get_global_id(1);
int index = width * globalIdy + globalIdx;
float a,b,c,d,e,f,g,h,i;
float sobelX = 0;
float sobelY = 0;
if(index > width && index < (height*width)-width && (index % width-1) > 0 && (index % width-1) < width-1){
a = A[index-1-width] * -1.0f;
b = A[index-0-width] * 0.0f;
c = A[index+1-width] * +1.0f;
d = A[index-1] * -2.0f;
e = A[index-0] * 0.0f;
f = A[index+1] * +2.0f;
g = A[index-1+width] * -1.0f;
h = A[index-0+width] * 0.0f;
i = A[index+1+width] * +1.0f;
sobelX = a+b+c+d+e+f+g+h+i;
a = A[index-1-width] * -1.0f;
b = A[index-0-width] * -2.0f;
c = A[index+1-width] * -1.0f;
d = A[index-1] * 0.0f;
e = A[index-0] * 0.0f;
f = A[index+1] * 0.0f;
g = A[index-1+width] * +1.0f;
h = A[index-0+width] * +2.0f;
i = A[index+1+width] * +1.0f;
sobelY = a+b+c+d+e+f+g+h+i;
}
R[index] = sqrt(pow(sobelX,2) + pow(sobelY,2));
}
1 回答
您链接的代码有一些低效率(没有特定的顺序):
在循环内的每个OpenCL调用之后调用clFinish是不必要的 . 首先,clEnqueueWriteBuffer和clEnqueueReadBuffer都使用阻塞设置为CL_TRUE,即在写/读完成之前它们不会返回(阻塞函数调用的定义) .
在将无符号字符图像发送到GPU之前,将其转换为浮动图像 . 这不是必需的,因为GPU能够使用unsigned char并且可以根据需要进行类型转换 . 在CPU上转换为float然后发送到GPU会导致发送4x数据量(每个通道每像素4个字节对1个字节) .
你调用cvWaitKey(10),暂停10毫秒等待按键,因此这段代码永远不会超过每秒100帧(次要问题) .
RGB到灰度转换可以在GPU上完成,但代价是发送3个无符号字符,因此需要进行权衡,需要进行测试 .
你的计时方法也存在缺陷 . 您的代码测量加载,处理和显示单个帧所花费的时间 . 处理包括OpenCL和OpenCV组件 . 您应该分别对这些中的每一个进行基准测试,以确定每个测试的时间长度,以便您可以准确确定瓶颈所处的位置 .
我刚刚想到的是OpenCV从中捕获的相机的帧速率是多少?