【问题标题】:OpenCL "read_image" Returns a Blank PixelOpenCL "read_image" 返回一个空白像素
【发布时间】:2014-06-18 12:50:36
【问题描述】:

问题描述和示例

我正在使用 OpenCL,并且正在尝试调整图像大小。我已经阅读了一些教程,并且几乎结束了尝试为此编写自己的内核。

我的问题是我无法让 OpenCL 从我传输到它的图像中读取像素

这是 OpenCL 中的内核:

const sampler_t SMPL_PREF = CLK_NORMALIZED_COORDS_TRUE |
                            CLK_ADDRESS_CLAMP |
                            CLK_FILTER_LINEAR;

__kernel void image_scaling( __read_only  image2d_t src_img,
                             __write_only image2d_t dest_img,
                                              float WRATIO,
                                              float HRATIO )
{
    int2       coor = (int2)( get_global_id(0), get_global_id(1) );

    float2 origCoor = (float2)(convert_float2(coor).x * WRATIO,
                               convert_float2(coor).y * HRATIO );

    uint4     color = read_imageui( src_img, SMPL_PREF, origCoor );

    // Test write_imageui -- THIS WORKS!!! :(
    //color = (uint4)(20, 255, 20, 255);

    write_imageui( dest_img, coor, color );
}

我正在使用 OpenCL.Net,但我认为这不是导致问题的原因。这就是我将图像从主机传输到设备内存的方式:

ImageFormat clImageFormat = new ImageFormat( ChannelOrder.RGBA,
                                             ChannelType.Unsigned_Int8 );

// Allocate Memory on Device
IMem inputImage2DBuffer = Cl.CreateImage2D( env.Context,
                                            MemFlags.AllocHostPtr |
                                                MemFlags.ReadOnly,
                                            clImageFormat,
                                   (IntPtr) originalWidth,
                                   (IntPtr) originalHeight,
                                   (IntPtr) 0,
                                   (IntPtr) 0, //imageData,
                                        out error );

// Copy the host data to the device
error = Cl.EnqueueWriteImage( env.CommandQueues[ 0 ],  // OpenCL Command Queue
                              inputImage2DBuffer,      // Ptr on device for image
                              Bool.True,               // Blocking write
                              originPtr,               // origin x,y (0,0)
                              regionPtrInput,          // dimension w,h
                     (IntPtr) 0,                       // rowPitch
                     (IntPtr) 0,                       // rowSlice
                              imageData,               // Ptr to byte[] host data
                              0,                       // Number of wait events
                              null,                    // array of wait events
                          out clEvent );

Cl.WaitForEvents( (uint) 1, new Event[] { clEvent } );
CheckError( error, "EnqueueWriteImage" );
clEvent.Dispose( );

我需要帮助

如果我没有将图像正确传输到设备或者我的设备有问题,如果有人可以建议一种调试方法,我会很高兴。我有点走投无路了。就像我说的,我不认为 OpenCL.Net 有问题,但我现在几乎愿意尝试任何事情。我认为在传输主机内存时我可能在做一些愚蠢的事情,但是我已经查看了该代码超过 100 次并重写了近十二次。我看到的任何东西都不会导致这个问题。

我知道我可以将常规缓冲区传输到设备并将其读回,读取图像是我唯一的问题。如果您查看我的 OpenCL 代码,您将看到一个注释行。通过取消注释,我可以将数据返回给我的主机(石灰绿色)。这导致人们相信问题出在 read_image 上。

我正在使用 Intel 5000 GPU 开发 2013 MacBook Air 来运行我的 OpenCL 代码。

【问题讨论】:

    标签: c# opencl opencl.net


    【解决方案1】:

    所以,在 Dithermaster 的帮助下(谢谢!),我已经解决了这个问题。问题是我在读回像素时没有使用归一化坐标。这是我当前的内核,它运行得非常好!


    调整大小.cl

    const sampler_t SMPL_PREF = CLK_NORMALIZED_COORDS_TRUE |
                                CLK_FILTER_LINEAR |
                                CLK_ADDRESS_NONE ;
    
    __kernel void image_scaling( __read_only  image2d_t src_img,
                                 __write_only image2d_t dest_img,
                                                   uint WIDTH,     // resized width
                                                   uint HEIGHT )   // resized height
    {
        int2       coor = (int2)( get_global_id(0), get_global_id(1) );
        float2 normCoor = convert_float2(coor) / (float2)( WIDTH, HEIGHT );
    
        float4    color = read_imagef( src_img, SMPL_PREF, normCoor );
    
        write_imagef( dest_img, coor, color );
    }
    

    再次感谢 Dithermaster 指出规格表。当涉及到过滤器标志和您使用的 read_image 时,OpenCL 非常具体。我很高兴我终于解决了这个问题:)

    【讨论】:

      【解决方案2】:

      根据您为 WRATIO 和 HRATIO 传递的值,问题与您使用 CLK_NORMALIZED_COORDS_TRUE 非常相似,并且应该可能使用 CLK_NORMALIZED_COORDS_FALSE。后者允许您使用像素坐标而不是 0.0 到 1.0 “标准化”坐标。

      另外,当您使用它时,请注意,对于 CLK_FILTER_LINEAR 和 float2 坐标,积分坐标将给出过滤结果。添加 (float2)(0.5f, 0.5f) 以获得未过滤的值。换句话说,对于 (2,6) 处的像素,读取 (2.5, 6.5)。当您的比率接近 1.0 时,这很重要,因此您不会得到模糊的图像。

      【讨论】:

      • 哦,所以“WRATIO = originalWidth / resizeWidth”(HRATIO 是高度)。我将尝试更改标志以不标准化坐标,我不知道它们的含义。
      • 终于要试试了。我可能从一开始就错了,但修复标志并没有真正解决我的问题。即使使用我以前的标志,我也会认为我至少会得到图像中的第一个像素(白色)。不过感谢您的建议,因为我认为我更近了一步...... :(
      • 我会删除缩放,看看你是否可以先获得一个直接的 1:1 图像副本,然后再添加缩放。另外,我刚刚注意到你正在使用 read_imageui,不支持 CLK_FILTER_LINEAR。您需要使用 read_imagef 和 UNORM 图像。查看 OpenCL 1.1 规范的第 6.11.13.2 节。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-27
      • 2012-06-03
      • 1970-01-01
      • 2016-03-31
      • 2019-12-20
      相关资源
      最近更新 更多