将OpenCL映像转换为pyOpenCL数组或numpy ndarray
我正试图使用Python和PyOpenCL为我在网上找到的代码中的图像实现一个高斯滤波器。我的原始图像是numpy阵列,但我不知道应该使用哪一个来将图像传递到GPU 最初,内核接收OpenCL图像作为输入。这工作正常,内核运行正常,但是,我还没有找到将GPU计算(也是OpenCL图像)的输出转换为numpy数组的方法。这是必需的,因为在运行GPU过滤器之后,我将不得不执行其他计算 我尝试使用pyOpenCL阵列,但在这种情况下有两个问题:将OpenCL映像转换为pyOpenCL数组或numpy ndarray,numpy,opencl,pyopencl,Numpy,Opencl,Pyopencl,我正试图使用Python和PyOpenCL为我在网上找到的代码中的图像实现一个高斯滤波器。我的原始图像是numpy阵列,但我不知道应该使用哪一个来将图像传递到GPU 最初,内核接收OpenCL图像作为输入。这工作正常,内核运行正常,但是,我还没有找到将GPU计算(也是OpenCL图像)的输出转换为numpy数组的方法。这是必需的,因为在运行GPU过滤器之后,我将不得不执行其他计算 我尝试使用pyOpenCL阵列,但在这种情况下有两个问题: 不知道如何告诉内核输入将是一个数组,因为它是一个pyOp
cl\u数组”
没有模块get()”错误image2d\t
说输入是一个图像一样李>
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
对象,并在内核调用中传递它们。这样,您就不必修改内核