Почему это ядро pyopencl не может правильно преобразовать скаляры в цвета?
Я написал ядро opencl для преобразования скалярных значений в цвета, потому что выполнение этого в обычном python занимает несколько секунд.
К сожалению, ядро (которое является урезанной версией некоторой логики, которая работает в другом месте), похоже, полностью не справляется со своей задачей преобразования из uint32 в триплеты из uint8 [sic] (r, g, b).
import numpy
import pyopencl as cl
from matplotlib.image import imsave
def generate_kernel(ctx):
return """
float3 hue_to_rgb(float hue)
{
float tmp = (hue-floor(hue))*6;
if (tmp<1) {
return (float3)( 1, tmp, 0);
} else if (tmp<2) {
float s = tmp-1;
float t = 2-tmp;
return (float3)( t, 1, 0);
} else if (tmp<3) {
float s = tmp-2;
float t = 3-tmp;
return (float3)(0, 1,s);
} else if (tmp<4) {
float s = tmp-3;
float t = 4-tmp;
return (float3)(0, t,1);
} else if (tmp<5) {
float s = tmp-4;
float t = 5-tmp;
return (float3)(s, 0,1);
} else {
float s = tmp-5;
float t = 6-tmp;
return (float3)(1, 0,t);
}
return (float3)(1,0,0);
}
__kernel void apply_color_map(__global uint*counts, __global uint8 *rgbs, int max_iter)
{
int idx = get_global_id(0);
int base = idx*3;
//printf("%d %d %d\\n", idx, base, counts[idx]);
if ( counts[idx] >= max_iter) {
rgbs[base] = 0;
rgbs[base+1] = 0;
rgbs[base+2] = 0;
} else {
float3 rgb = 255.9f*hue_to_rgb(counts[idx]/255.0f);
rgb.x = 0x80; // yeah, even something as simple as this does not work
rgb.y = 0x0;
rgb.z = 0x0;
rgbs[base] = floor(rgb.x);
rgbs[base+1] = floor(rgb.y);
rgbs[base+2] = floor(rgb.z);
//printf(" %v3f\\n", rgb);
//printf("counts[%d] = %d ; %v3f <%x,%u,%u>\\n", idx, counts[idx], rgb, rgbs[base], rgbs[base+1], rgbs[base+2]);
}
}
"""
def mission1(ctx, queue):
source = generate_kernel(ctx)
print (source)
prg = cl.Program(ctx, source).build()
width=256
height=16
#counts = numpy.load("/tmp/mandelbrot.npy");
counts = [ [x for x in range(width)] for y in range(height) ]
counts = numpy.array(counts, dtype=numpy.uint32)
print(counts)
kernel = prg.apply_color_map
kernel.set_scalar_arg_dtypes([None, None, numpy.uint32])
counts_len = width*height
counts_g = cl.Buffer(ctx, cl.mem_flags.READ_ONLY, counts_len*4)
rgb_g = cl.Buffer(ctx, cl.mem_flags.READ_WRITE, counts_len*3)
rgb = numpy.zeros([height,width,3], dtype=numpy.uint8)
cl.enqueue_copy(queue, counts_g, counts).wait()
kernel(queue, [width*height], None, counts_g, rgb_g, 256) .wait()
cl.enqueue_copy(queue, rgb, rgb_g).wait()
imsave("/tmp/ramp.png", rgb)
#
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)
mission1(ctx, queue)
Я ожидаю, что выходное изображение будет выглядеть как сплошной темно-красный (потому что я заменяю значения радуги в качестве теста отладки), но оно выглядит как некоторые странные полосы и блоки шума.
1 ответ
Очевидно, мне нужно изменить
__kernel void apply_color_map(__global uint*counts, __global uint8 *rgbs, int max_iter)
в
__kernel void apply_color_map(__global uint*counts, __global unsigned char *rgbs, int max_iter)
Если кто-то может указать на документацию, которая объясняет, почему unsigned char
а также uint8
отличаются от pyopencl в этом контексте, я приму их ответ.