图像旋转
源代码需要在clEnqueueNDRangeKernel函数执行之后注释掉
waitForEventAndRelease() //或者//
clWaitForEvents(1,&ev)
因为wait函数在结束时释放了ev,而下一个函数cl的功能其实和wait类似,也要访问ev变量,所以如果两个函数串行执行,后执行的那个会找不到那个变量,相当于访问空指针,会报段错误。
实验结果:
CPU旋转的结果
CPU
用OpenCL进行旋转的结果
OpenCL
边缘检测
CPU
需要和旋转一样调用cv.h,方法是将编译语句-o命名和-lOpenCL中间加一个调用
`pkg-config --cflags --libs opencv`
然后方法是直接调用sobel函数,参数分别为
sobel(Mat类型输入,输出,输出图像深度,x方向差分阶数,y方向...,核大小,缩放因子,delta值,边界模式)
深度ddepth取CV_16S;核大小默认3可调,缩放因子默认1,delta默认0,边界模式默认BORDER_DEFAULT。
如果做x方向上的sobel运算,则x方向差分阶数=1,y方向=0.
反之亦然。
将两个反向的结果做近似处理,即调用addweighted()函数,指数设为0.5,作类似求勾股的操作。得到每个元素的梯度,输出即是被强化后的边缘。
结果 CPU效果图
OpenCL方面的运算我参考了https://software.intel.com/en-us/INDE-OpenCL-Sobel,这里的思路是:
__kernel void Sobel_v1_uchar (__global uchar *pSrcImage, __global uchar *pDstImage)
{
uint dstYStride = get_global_size(0);
uint dstIndex = get_global_id(1) * dstYStride + get_global_id(0);
uint srcYStride = dstYStride + 32;
uint srcIndex = get_global_id(1) * srcYStride + get_global_id(0) + 16;
uint a, b, c;
uint d, /*center*/ f;
uint g, h, i;
// Read data in
a = pSrcImage[srcIndex-1]; b = pSrcImage[srcIndex]; c = pSrcImage[srcIndex+1];
srcIndex += srcYStride;
d = pSrcImage[srcIndex-1]; /*center*/ f = pSrcImage[srcIndex+1];
srcIndex += srcYStride;
g = pSrcImage[srcIndex-1]; h = pSrcImage[srcIndex]; i = pSrcImage[srcIndex+1];
uint xVal = a* 1 + c*-1 +
d* 2 + /*center*/ f*-2 +
g* 1 + i*-1;
uint yVal = a* 1 + b* 2 + c* 1 +
/*center*/
g*-1 + h*-2 + i*-1;
// Write data out
pDstImage[dstIndex] = min((uint)255, (uint)sqrt(xVal*xVal + yVal*yVal));
}
仿照平时对图像处理的方法,一个workitem处理一个像素,对每一个像素周围的3x3区域的每个像素点进行两个方向上的卷积处理,然后再平方后求和开方。
网友评论