【问题标题】:Grayscale Image in OpenCLOpenCL 中的灰度图像
【发布时间】:2014-08-06 03:51:13
【问题描述】:

我想将 RGB 图像转换为灰度图像。

我的问题是,图像是缩放的,但分辨率保持不变。 这里是一个例子:Images

OpenCL 代码似乎是正确的:

const sampler_t sampler =   CLK_NORMALIZED_COORDS_FALSE |
                            CLK_ADDRESS_CLAMP_TO_EDGE |
                            CLK_FILTER_NEAREST;

__kernel void grayscale(__read_only  image2d_t src,
                        __write_only image2d_t dst)
{
    int x = get_global_id(0);
    int y = get_global_id(1);

    uint4 color;

    color = read_imageui(src, sampler, (int2)(x, y));
    uint gray = (color.x + color.y + color.z) / 3;
    write_imageui(dst, (int2)(x,y), (uint4)(gray, gray, gray, 0));
}

看来我在对象的大小或 BufferedImage 本身上犯了一个错误 (注意:cl-class 仅用于获取 cl COMmandqueue/device/... 的实例)

cl_program  prog;
        cl_kernel   kernel;
        String      kernelSrc = null;
        int[] err = new int[1];
        BufferedImage grayimg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        // --------------------

        // Get the Sourcecodes
        try {
            kernelSrc  = CLFileLoader.GetSource(KERNEL_GRAYSCALE_PATH);
        }
        catch(IOException exc) {
            System.err.println("Error while loading Kernelfile: " + exc);
        }

        prog = clCreateProgramWithSource(cl.getContext(), 1, new String[] {kernelSrc}, null, err);
        clBuildProgram(prog, 0, null, null, null, err);
        kernel = clCreateKernel(prog, "grayscale", err);

        if(err[0] != CL_SUCCESS) {
            System.err.println("Couldnt create Graykernel");
            System.exit(1);
        }        
        byte dataBuffer[] = ((DataBufferByte)img.getRaster().getDataBuffer()).getData();

        cl_image_format imageFormat = new cl_image_format();
        imageFormat.image_channel_data_type = CL_UNSIGNED_INT8;
        imageFormat.image_channel_order = CL_RGBA;

        cl_image_format formats[] = new cl_image_format[1];
        formats[0] = imageFormat;

        cl_mem input = clCreateImage2D(cl.getContext(), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, formats, img.getWidth(),
                img.getHeight(), 0, Pointer.to(dataBuffer), err);
        cl_mem output = clCreateImage2D(cl.getContext(), CL_MEM_WRITE_ONLY, formats, img.getWidth(),
                img.getHeight(), 0, null, err);

        if(err[0] != CL_SUCCESS) {
            System.err.println("Couldnt create objects");
            System.exit(1);
        }

        // Set Args
        clSetKernelArg(kernel, 0, Sizeof.cl_mem, Pointer.to(input));
        clSetKernelArg(kernel, 1, Sizeof.cl_mem, Pointer.to(output));

        // Transfer Image to the OpenCL-Device
        if(clEnqueueWriteImage(cl.getCommandQueue(), input, CL_TRUE, 
                new long[] {0,0,0}, new long [] {img.getWidth(), img.getHeight(), 1}, 
                img.getWidth(), 0, Pointer.to(dataBuffer), 0, null, null) != CL_SUCCESS) {
            System.err.println("Cant write Image");
            System.exit(1);
        }

        long workSize[] = new long[] {img.getWidth(), img.getHeight()};
        long workSizelocal[] = new long[] {2,2};

        if(clEnqueueNDRangeKernel(cl.getCommandQueue(), kernel, 2, null, 
                workSize, workSizelocal, 0, null, null) != CL_SUCCESS) {
            System.err.println("Cant apply Blackwhite-kernel");
            System.exit(1);
        }

        byte grayimg_byte[] = ((DataBufferByte)grayimg.getRaster().getDataBuffer()).getData();

        if(clEnqueueReadImage(cl.getCommandQueue(), output, CL_TRUE, new long[] {0,0,0}, 
                new long[] {img.getWidth(), img.getHeight(), 1}, img.getWidth(), 0, Pointer.to(grayimg_byte), 0, null, null) != CL_SUCCESS) {
            System.err.println("Cant read values from Blackwhite-kernel");
            System.exit(1);
        }

        clReleaseMemObject(input);
        clReleaseMemObject(output);

        return grayimg;

最好的问候

【问题讨论】:

  • RGB 是原始色彩空间吗?如果原始的是 YCbCr(例如 JPEG 图像),则工作已经完成 - 只需拉原始 Y 平面。
  • 我猜你正在以其他格式(UINT32)复制图像,这就是为什么你在处理时只得到它的 1/4。它不会崩溃,因为您将指针指向 OpenCL API,它只占用必要的部分。
  • 你能发布一张结果的图片吗?你说它是“放大”的?
  • 我在上面发布了两个图片的链接。加载的图像是 3BYTE_BGR

标签: java bytearray opencl bufferedimage jocl


【解决方案1】:

我根本不知道 OpenCL,但是你是否应该只写一个灰度值而不是三个,在这里

   write_imageui(dst, (int2)(x,y), (uint4)(gray, gray, gray, 0));

我的意思是删除,gray,gray。我认为这是因为您将 CL_UNSIGNED_INT8 作为类型,但您正在编写一个无符号的 32 位 int。

顺便说一句,还有其他方法可以从 RGB 计算灰度值,请参阅here,如果使用,您可能会得到比仅平均 R + G + B 更好的结果

Gray = 0.21 R + 0.72 G + 0.07 B

【讨论】:

  • write_imageui 函数需要一个 int4 作为 3. 参数。感谢您提供有关光度方法的信息。
  • CL_UNSIGNED_INT8 表示每通道 8 位 (khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/…)
  • 我认为函数调用没问题,问题可能在OpenCL之外,当复制发生时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-28
  • 1970-01-01
  • 1970-01-01
  • 2014-09-15
  • 1970-01-01
相关资源
最近更新 更多