PyOpenCL сокращение Ядро на каждый пиксель изображения в виде массива вместо каждого байта (режим RGB, 24 бита)

Я пытаюсь вычислить среднюю яркость изображения RGB. Для этого я нахожу яркость каждого пикселя, т.е.

L(r,g,b) = X*r + Y*g + Z*b (some linear combination).

А затем найдите среднее значение, суммируя яркость всех пикселей и деля на ширину * высоту. Чтобы ускорить это, я использую pyopencl.reduction.ReductionKernel

Массив, который я передаю ему, представляет собой Single Dimension Numpy Array, поэтому он работает так же, как и в приведенном примере.

import Image
import numpy as np
im = Image.open('image_00000001.bmp')
data = np.asarray(im).reshape(-1) # so data is a single dimension list
# data.dtype is uint8, data.shape is (w*h*3, )

Я хочу включить в него следующий код из примера. т.е. я бы внес изменения в тип данных и тип массивов, которые я передаю. Это пример:

a = pyopencl.array.arange(queue, 400, dtype=numpy.float32)
b = pyopencl.array.arange(queue, 400, dtype=numpy.float32)

krnl = ReductionKernel(ctx, numpy.float32, neutral="0",
        reduce_expr="a+b", map_expr="x[i]*y[i]",
        arguments="__global float *x, __global float *y")

my_dot_prod = krnl(a, b).get()

За исключением того, что мой map_expr будет работать с каждым пикселем и преобразовывать каждый пиксель в его значение яркости. И уменьшить expr остается прежним.

Проблема в том, что он работает с каждым элементом массива, и мне нужно, чтобы он работал с каждым пикселем, который состоит из 3 последовательных элементов одновременно (RGB).

Одно из решений состоит в том, чтобы иметь три разных массива, один для R, один для G и один для B, что сработало бы, но есть ли другой способ?

1 ответ

Решение

Изменить: я изменил программу, чтобы проиллюстрировать использование char4 вместо float4:

import numpy as np
import pyopencl as cl
import pyopencl.array as cl_array


deviceID = 0
platformID = 0
workGroup=(1,1)

N = 10
testData = np.zeros(N, dtype=cl_array.vec.char4)

dev = cl.get_platforms()[platformID].get_devices()[deviceID]

ctx = cl.Context([dev])
queue = cl.CommandQueue(ctx)
mf = cl.mem_flags
Data_In = cl.Buffer(ctx, mf.READ_WRITE, testData.nbytes)


prg = cl.Program(ctx, """

__kernel void   Pack_Cmplx( __global char4* Data_In, int  N)
{
  int gid = get_global_id(0);

  //Data_In[gid] = 1; // This would change all components to one
  Data_In[gid].x = 1;  // changing single component
  Data_In[gid].y = 2;
  Data_In[gid].z = 3;
  Data_In[gid].w = 4;
}
 """).build()

prg.Pack_Cmplx(queue, (N,1), workGroup, Data_In, np.int32(N))
cl.enqueue_copy(queue, testData, Data_In)
print testData

Я надеюсь, что это помогает.

Другие вопросы по тегам