将OpenCL映像转换为pyOpenCL数组或numpy ndarray

将OpenCL映像转换为pyOpenCL数组或numpy ndarray,numpy,opencl,pyopencl,Numpy,Opencl,Pyopencl,我正试图使用Python和PyOpenCL为我在网上找到的代码中的图像实现一个高斯滤波器。我的原始图像是numpy阵列,但我不知道应该使用哪一个来将图像传递到GPU 最初,内核接收OpenCL图像作为输入。这工作正常,内核运行正常,但是,我还没有找到将GPU计算(也是OpenCL图像)的输出转换为numpy数组的方法。这是必需的,因为在运行GPU过滤器之后,我将不得不执行其他计算 我尝试使用pyOpenCL阵列,但在这种情况下有两个问题: 不知道如何告诉内核输入将是一个数组,因为它是一个pyOp

我正试图使用Python和PyOpenCL为我在网上找到的代码中的图像实现一个高斯滤波器。我的原始图像是numpy阵列,但我不知道应该使用哪一个来将图像传递到GPU

最初,内核接收OpenCL图像作为输入。这工作正常,内核运行正常,但是,我还没有找到将GPU计算(也是OpenCL图像)的输出转换为numpy数组的方法。这是必需的,因为在运行GPU过滤器之后,我将不得不执行其他计算

我尝试使用pyOpenCL阵列,但在这种情况下有两个问题:

  • 不知道如何告诉内核输入将是一个数组,因为它是一个pyOpenCL数据结构,而不是OpenCL数据结构
  • 在pyOpenCL数组上找不到与read_imagef等效的函数,我在内核中使用该函数
  • 无法将GPU结果复制回主机。我会一直得到一个“
    cl\u数组”
    没有模块get()”错误
  • 我想知道:

  • 有没有一种方法可以告诉内核它将接收一个数组,就像我用
    image2d\t
    说输入是一个图像一样
  • 对于pyOpenCL数组,我可以使用什么作为OpenCL的
    read\u imagef
    的等价物
  • 先谢谢你。内核代码如下:

    内核:

    __kernel void gaussian(__read_only image2d_t inputImage,
                            __read_only image2d_t filterImage,
                            __write_only image2d_t outputImage,
                            const int nInWidth,
                            const int nFilterWidth){
    
    const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;
    
    const int xOut = get_global_id(0);
    const int yOut = get_global_id(1);
    
    float4 sum = (float4)(0.0, 0.0, 0.0, 1.0);
    
    for(int r = 0; r < nFilterWidth; r++){
        for(int c = 0; c < nFilterWidth; c++){
    
            int2 location = (xOut + r, yOut + c);
    
            float4 filterVal = read_imagef(filterImage, sampler, location);
            float4 inputVal = read_imagef(inputImage, sampler, location);
    
            sum.x += filterVal.x * inputVal.x;
            sum.y += filterVal.y * inputVal.y;
            sum.z += filterVal.z * inputVal.z;
            sum.w = 1.0;
        }
    }
    
    int2 outLocation = (xOut, yOut);
    write_imagef(outputImage, outLocation, sum);
    }
    
    \uuuuu内核无效高斯(\uuuu只读图像2d\u t输入图像,
    __只读图像2D\t过滤器图像,
    __仅写入图像2D输出图像,
    const int nInWidth,
    常量(整型过滤器宽度){
    常量采样器\u t采样器=CLK\u规范化\u坐标\u假| CLK\u地址\u钳位\u到边| CLK\u过滤器\u最近;
    const int xOut=get\u global\u id(0);
    const int yOut=get_global_id(1);
    浮动4总和=(浮动4)(0.0,0.0,0.0,1.0);
    for(int r=0;r
    这是一个复杂的问题,因为我有同样的问题,所以我想尝试详细回答。让我们把你的问题分解成更小的部分,看看发生了什么

    数据类型

    您似乎混淆了一些相互关联的数据类型。OpenCL本身使用图像或数组,pyopenCL数组映射到OpenCL中的数组,pyopenCL图像映射到OpenCL图像也是如此。在某些特殊情况下,混合使用这两种方法会奏效,但总的来说,这不是一个好主意

    数据访问

    OpenCL中的图像需要一个采样器来读取。在python中,可以通过简单的坐标访问来访问数组。(有关我在那里遇到的问题,请参阅或获取更多信息…)

    移动


    使用pyopencl在OpenCL中移动的所有东西都有自己的复制功能。因此,要将映像或数组从设备移动到主机,请确保将相应的复制函数排入上下文中的队列。

    pyopencl.array的底层OpenCl数据结构是所谓的缓冲区。可以通过数组的
    base\u data
    属性检索缓冲区对象(请参阅)。缓冲区可以在内核调用中传递,但是必须调整内核以处理缓冲区而不是图像(将内核参数类型更改为
    \u global float*inputImage
    等,访问元素,如在常规多维数组索引中)

    无论如何,PyOpenCL数组类被设计为使用numpy风格编写代码,这些代码将在设备上执行。这不再需要您自己编写任何内核代码。相反,您可以这样做:

    import pyopencl as cl
    input_array = cl.array.to_device(queue, input_numpy_array)
    filter_array = cl.array.to_device(queue, filter_numpy_array)
    output_array = cl.array.zeros_like(input_array)
    # half height and half width of filter
    fhh, fhw = filter_array.shape[0] // 2, filter_array.shape[1] // 2
    for y in range(input_array.shape[0]):
        for x in range(input_array.shape[1]):
                patch = input_array[y-fhh:y+fhh+1, x-fhw:x+fhw+1]
            sum = cl.array.sum(patch * filter_array)
            output_array[y, x] = sum
    output_numpy_array = output_array.get()
    
    注意,我假设使用单通道(灰色)图像。此外,我没有测试上面的代码,但我认为实现效率非常低。不包括边缘处理

    <强>最后,使用PyopCl数组,考虑内核,应该考虑<强>不<强>。从numpy数组中创建

    pyopencl.Image
    对象,并在内核调用中传递它们。这样,您就不必修改内核