Hough变换与OpenCL
我试图在OpenCL中实现圆的Hough变换,但我遇到了一个非常奇怪的问题。每次运行Hough内核时,我都会使用稍微不同的累加器,即使参数相同,累加器始终是一个新的零表(例如)。我的内核代码如下:Hough变换与OpenCL,opencl,gpgpu,hough-transform,Opencl,Gpgpu,Hough Transform,我试图在OpenCL中实现圆的Hough变换,但我遇到了一个非常奇怪的问题。每次运行Hough内核时,我都会使用稍微不同的累加器,即使参数相同,累加器始终是一个新的零表(例如)。我的内核代码如下: #define BLOCK_LEN 256 __kernel void HoughCirclesKernel( __global int* A, __global int* imgData, __global int* _width, __global int* _h
#define BLOCK_LEN 256
__kernel void HoughCirclesKernel(
__global int* A,
__global int* imgData,
__global int* _width,
__global int* _height,
__global int* r
)
{
__local int imgBuff[BLOCK_LEN];
int localThreadIndex = get_local_id(0); //threadIdx.x
int globalThreadIndex = get_local_id(0) + get_group_id(0) * BLOCK_LEN; //threadIdx.x + blockIdx.x * Block_Len
int width = *_width; int height = *_height;
int radius = *r;
A[globalThreadIndex] = 0;
barrier(CLK_GLOBAL_MEM_FENCE);
if(globalThreadIndex < width*height)
{
imgBuff[localThreadIndex] = imgData[globalThreadIndex];
barrier(CLK_LOCAL_MEM_FENCE);
if(imgBuff[localThreadIndex] > 0)
{
float s1, c1;
for(int i = 0; i<180; i++)
{
s1 = sincos(i, &c1);
int centerX = globalThreadIndex % width + radius * c1;
int centerY = ((globalThreadIndex - centerX) / height) + radius * s1;
if(centerX < width && centerY < height)
atomic_inc(A + centerX + centerY * width);
}
}
}
barrier(CLK_GLOBAL_MEM_FENCE);
}
#定义块长度256
__核空HoughCirclesKernel(
__全局整数*A,
__全局整数*imgData,
__全局整数*宽度,
__全局整数*高度,
__全局整数*r
)
{
__本地int imgBuff[块_LEN];
int localThreadIndex=get_local_id(0);//threadIdx.x
int globalThreadIndex=get_local_id(0)+get_group_id(0)*BLOCK_LEN;//threadIdx.x+blockIdx.x*BLOCK_LEN
整数宽度=*\u宽度;整数高度=*\u高度;
整数半径=*r;
A[globalThreadIndex]=0;
屏障(CLK_GLOBAL_MEM_围栏);
if(全局线程索引<宽度*高度)
{
imgBuff[localThreadIndex]=imgData[globalThreadIndex];
屏障(CLK_本地_MEM_围栏);
如果(imgBuff[localThreadIndex]>0)
{
浮球s1、c1;
对于(int i=0;i
这里的get_group_id(0)是指每个设备的get_group_id,所有设备的get_group_id都从0开始,正如get_global_id也从零开始一样;因此您应该在“ndrange”中添加适当的偏移量使用多个设备时的说明。即使不同的设备可以支持相同的浮点精度要求,但其中一个设备的精度可能比另一个设备的精度高,结果可能略有不同。如果是单个设备,则应尝试降低gpu频率,因为它可能有缺陷或超频的副作用
这里的get_group_id(0)是指每个设备的get_group_id,所有设备的get_group_id都从0开始,正如get_global_id也从零开始一样;因此您应该在“ndrange”中添加适当的偏移量使用多个设备时的说明。即使不同的设备可以支持相同的浮点精度要求,但其中一个设备的精度可能比另一个设备的精度高,结果可能略有不同。如果是单个设备,则应尝试降低gpu频率,因为它可能有缺陷或超频的副作用。I h我发现并纠正了三个问题,从而解决了我的问题
首先是内核代码,行:
int centerY = ((globalThreadIndex - centerX) / height) + radius * s1;
应该是:
int centerY = (globalThreadIndex / width) + radius * s1;
这里的主要变化是除以宽度,而不是高度。这导致了不准确的问题
if(centerX < width && centerY < height)
这里的解决方法很简单,而且几乎是自我解释的:
int[] a = Enumerable.Repeat(0, width * height).ToArray();
ErrorCode error;
GCHandle accHandle = GCHandle.Alloc(a, GCHandleType.Pinned);
IntPtr accPtr = accHandle.AddrOfPinnedObject();
Mem cl_accumulator = (Mem)Cl.CreateBuffer(cl_context, MemFlags.ReadWrite | MemFlags.CopyHostPtr, (IntPtr)(a.Length * sizeof(int)), accPtr, out error);
CheckErr(error, "Cl.CreateBuffer");
我用零填充累加器表,然后在每次执行内核时将其复制到设备缓冲区
上述错误导致每次执行内核时累加器看起来都不一样,并且出现了位错误。我通过查找并纠正三个问题,成功地解决了我的问题
首先是内核代码,行:
int centerY = ((globalThreadIndex - centerX) / height) + radius * s1;
应该是:
int centerY = (globalThreadIndex / width) + radius * s1;
这里的主要变化是除以宽度,而不是高度。这导致了不准确的问题
if(centerX < width && centerY < height)
这里的解决方法很简单,而且几乎是自我解释的:
int[] a = Enumerable.Repeat(0, width * height).ToArray();
ErrorCode error;
GCHandle accHandle = GCHandle.Alloc(a, GCHandleType.Pinned);
IntPtr accPtr = accHandle.AddrOfPinnedObject();
Mem cl_accumulator = (Mem)Cl.CreateBuffer(cl_context, MemFlags.ReadWrite | MemFlags.CopyHostPtr, (IntPtr)(a.Length * sizeof(int)), accPtr, out error);
CheckErr(error, "Cl.CreateBuffer");
我用零填充累加器表,然后在每次执行内核时将其复制到设备缓冲区
上述错误导致每次执行内核时累加器看起来都不一样,并且格式有点不正确。请发布一个可运行的示例,再现您的错误。我尝试编写一个累加器时,每次都正常运行并产生相同的结果,但是,当然,在您没有显示给我们的部分可能会发生一些事情。顺便说一下,您可以t通过height
、width
和r
作为标量,不需要使用单元素数组。另外,如果可能,请在另一台设备上测试您的程序。此外,使用Python与numpy
、matplotlib
和pyopencl
。我在这里上传了整个解决方案,因为我的另一个项目是不规则的Hough变换似乎工作得很好,圆圈就是基于它的。不幸的是,我没有VS来编译它,但程序看起来很好。也许有Windows的人可以提供更多帮助。需要尝试的事情:在不同的设备上运行;试着运行我的代码(如上)。检查编译器/驱动程序问题:将标量作为标量而不是数组传递;预先用零填充A
,而不是在内核中;删除本地内存使用情况(此处不需要);通过累加器单元而不是图像像素进行并行化(不需要使用atomic_inc
)。请发布一个可运行的示例,再现您的错误。我尝试编写一个示例时运行正常,每次都会产生相同的结果,但是,当然,在您没有显示给我们的部分中可能会发生一些事情。顺便说一下,您可以将高度、宽度和r
作为标量传递,无需使用1元素数组。P.S。如果可能的话,请在另一台设备上测试您的程序。另外,将Python与numpy
、matplotlib
和pyopencl
一起使用。我在这里上传了整个解决方案,它看起来很有意思,因为我的另一个项目是不规则Hough变换,它似乎工作得很好,圆圈就是基于它的。不幸的是,我没有VS编译它,但程序看起来很好。也许有Windows的人可以提供更多帮助。要尝试的事情:在不同的设备上运行;尝试运行我的代码(如上)。检查编译器/驱动程序问题:将标量作为标量而不是数组传递;预先用零填充a
,而不是在内核中;删除本地内存使用情况(此处不需要)在累加器单元上并行化,而不是图像像素(无需采用这种方式atomic_inc
)。
int[] a = Enumerable.Repeat(0, width * height).ToArray();
ErrorCode error;
GCHandle accHandle = GCHandle.Alloc(a, GCHandleType.Pinned);
IntPtr accPtr = accHandle.AddrOfPinnedObject();
Mem cl_accumulator = (Mem)Cl.CreateBuffer(cl_context, MemFlags.ReadWrite | MemFlags.CopyHostPtr, (IntPtr)(a.Length * sizeof(int)), accPtr, out error);
CheckErr(error, "Cl.CreateBuffer");