AgUn
AgUn

Reputation: 33

pyopencl kernel outputs black image

Why is the image coming out as black when saved? I am just beginning to learn opencl. Without opencl, on purely CPU, the loop iterates through the matrix and uses the rgb2gray average formula to store the values in gray array. Using windows and python 3.8

import pyopencl
import numpy as np
import imread
import matplotlib.pyplot as plt

ocl_platforms = (platform.name for platform in pyopencl.get_platforms())
print("\n".join(ocl_platforms))
# select platform
platform = pyopencl.get_platforms()[0]
# select device
device = platform.get_devices()[0]

# create context
ctx = pyopencl.Context(devices=[device])

img = imread.imread('gigapixel.jpg')

r = np.array(img[:, :, 0], dtype=np.float32)

g = np.array(img[:, :, 1], dtype=np.float32)

b = np.array(img[:, :, 2], dtype=np.float32)
gray = np.empty_like(r)
# without gpu
for i in range(r.shape[0]):
    for j in range(r.shape[1]):
        gray[i, j] = (r[i, j] + g[i, j] + b[i, j]) / 3
plt.imshow(gray)
plt.show()
# convert to uint8
gray = np.uint8(gray)
# save image
imread.imsave('gray_cpu.jpg', gray)

with GPU the rest of the code is

gray = np.empty_like(r)
program_source = """
__kernel void rgb2gray(__global float *r, __global float *g, __global float *b, __global 
float *gray) {
int i = get_global_id(0);
int j = get_global_id(1);
gray[i, j] = (r[i, j] + g[i, j] + b[i, j])/ 3;
}
"""
gpu_program_source = pyopencl.Program(ctx, program_source)
gpu_program = gpu_program_source.build()
program_kernel_names = gpu_program.get_info(pyopencl.program_info.KERNEL_NAMES)
print(program_kernel_names)

queue = pyopencl.CommandQueue(ctx)

r_buf = pyopencl.Buffer(ctx, pyopencl.mem_flags.READ_ONLY |             
pyopencl.mem_flags.COPY_HOST_PTR, hostbuf=r)
g_buf = pyopencl.Buffer(ctx, pyopencl.mem_flags.READ_ONLY | 
pyopencl.mem_flags.COPY_HOST_PTR, hostbuf=g)
b_buf = pyopencl.Buffer(ctx, pyopencl.mem_flags.READ_ONLY |     
pyopencl.mem_flags.COPY_HOST_PTR, hostbuf=b)
gray_buf = pyopencl.Buffer(ctx, pyopencl.mem_flags.WRITE_ONLY, r.nbytes)

gpu_program.rgb2gray(queue, r.shape, None, r_buf, g_buf, b_buf, gray_buf)

pyopencl.enqueue_copy(queue, gray, gray_buf)


plt.imshow(gray)
plt.show()

gray = np.uint8(gray)

imread.imsave('gigapixel_gray.jpg', gray)

Upvotes: 1

Views: 140

Answers (1)

huseyin tugrul buyukisik
huseyin tugrul buyukisik

Reputation: 11920

If you need to keep the array[x,y] notation, then try Numba instead of PyOpenCL. Numba converts Python function's bytecode into OpenCL kernels.

PyOpenCL is only a wrapper over OpenCL API so it compiles the given kernel code for C or C++ languages directly. So you need to index like this:

int i = get_global_id(0);
int j = get_global_id(1);
gray[i][j] = (r[i][j] + g[i][j] + b[i][j])/ 3;

If you want to see the errors produced at any stage(kernel compiling, buffer copying, etc), you need to catch exceptions of Python because PyOpenCL binds OpenCL-errors to Python exceptions. You should check them like this:

try:
  your_opencl_accelerated_function()
except:
  print("Something didn't work") 

Upvotes: 0

Related Questions