Hough变换与OpenCL

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

我试图在OpenCL中实现圆的Hough变换,但我遇到了一个非常奇怪的问题。每次运行Hough内核时,我都会使用稍微不同的累加器,即使参数相同,累加器始终是一个新的零表(例如)。我的内核代码如下:

#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");