2015-10-16 3 views
2

Я пытаюсь реализовать гауссовский фильтр для изображений из кода, который я нашел в Интернете, используя Python и PyOpenCL. Мои исходные изображения - массивы numpy, но я смущен, как в том, что я должен использовать для передачи изображений на графический процессор.Преобразование OpenCL в pyOpenCL Array или numpy ndarray

Первоначально ядро ​​получает изображения OpenCL в качестве входных данных. Это работает отлично, и ядро ​​работает правильно, однако я не нашел способ преобразовать вывод вычисления графического процессора (также OpenCL Image) в массив numpy. Это необходимо, так как после запуска фильтра GPU мне придется выполнять другие вычисления.

Я попытался с помощью pyOpenCL массива, но было 2 проблемы в этом случае:

  1. Не знаю, как сказать ядру, что вход будет массив, так как она представляет собой структуру данных pyOpenCL, не OpenCL.
  2. Не нашел эквивалент read_imagef, который будет использоваться в массивах pyOpenCL, и я использую эту функцию в своем ядре.
  3. Не удалось получить результат GPU, скопированный обратно на хост. Я бы продолжал получать «cl_array не имеет ошибки get()» модуля.

Я хотел бы знать:

  1. Есть ли способ, чтобы сообщить ядру, что он получит массив, так же, как я использую image2d_t сказать, что вход является изображение?
  2. Что я могу использовать в качестве эквивалента для OpenCL's read_imagef для массивов pyOpenCL?

Большое спасибо заранее. Код ядра ниже:

Ядро:

__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); 
} 

ответ

2

Это сложный вопрос, и я имел те же вопросы, которые я хочу, чтобы попытаться ответить на них подробно. Давайте разберем ваши проблемы на более мелкие части, чтобы посмотреть, что происходит.

Datatypes

Вы, кажется, путают некоторые типы данных, которые друг друга. OpenCL само по себе использует изображения или массивы, а pyopenCL массив карты в массив в OpenCL, то же самое делает pyopenCL изображение к OpenCL изображения. Смешение этих двух будет работать в некоторых особых случаях, но в целом это не очень хорошая идея.

данных Доступ

изображение в OpenCL необходим пробник для чтения из него. Доступ к массиву осуществляется с помощью простого доступа к координированию, как в python. (См. here или here для получения дополнительной информации о проблемах, которые у меня были там ...).

Движение

Все, что вы двигаться в OpenCL с помощью pyopencl имеет собственные функции копирования.Таким образом, для перемещения изображения или массива с устройства на хост, обязательно установите в очередь соответствующую функцию копирования в очередь в вашем контексте.

0

Основой структуры данных OpenCl pyopencl.Array является так называемый буфер. Вы можете получить объект буфера с помощью атрибута base_data массива (см. the docs). Буфер может быть передан в вызове ядра, однако ядро ​​должно быть настроено для обработки буферов, а не изображений (изменить тип аргумента ядра на __global float* inputImage и т. Д., Элементы доступа, как при регулярном многомерном индексировании массива).

В любом случае класс PyOpenCL Array предназначен для написания кода с использованием стиля 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() 

Обратите внимание, что я предположил использование одноканального (серого) изображения. Также я не тестировал код выше, но я предполагаю, что реализация будет ужасно неэффективной. Обработка кромок не покрывается.

Наконец, вы должны рассмотреть не с помощью PyOpenCl Массивы, учитывая ваше ядро. Создайте pyopencl.Image объекты из ваших массивов numpy и передайте их в ядре. Таким образом, вам не нужно изменять свое ядро.