c++ - 使用 OpenCL 的图像卷积中的参数大小无效

标签 c++ image opencl convolution

我正在尝试将 OpenCV 结合起来,以便于图像和 OpenCL 的使用。 任务是加载图像并将其转换为具有浮点像素值的灰度。 然后我想用filte做图像卷积。

当我尝试执行内核时,我收到错误消息: “clEnqueueReadImage:错误代码 -30” -> CL_INVALID_VALUES

我在回读结果时似乎得到了无效值" 有人可以帮我找出错误吗?

#define _CRT_SECURE_NO_WARNINGS
#define __CL_ENABLE_EXCEPTIONS

#define PROGRAM_FILE "convolution.cl"
#define KERNEL_FUNC "laplacianFilter"

#include <iostream>
#include <fstream>
#include <CL/cl.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

int main()
{
    //////////////////////////////////////////////////////////////////////////
    //PREPROCESSING
    //////////////////////////////////////////////////////////////////////////
    cv::Mat Input, Input_f;
    cv::Mat Output, Output_f;

    //Load the Image and convert it to grayscale as float
    Input = cv::imread("hqdefault.jpg", 0);                         //loads image as grayscale; 1 channel
    //Input.convertTo(Input_f, CV_32FC1, 1/255.0);                  //scale or convert the image back later
    Input.convertTo(Input_f, CV_32FC1);

    //Create output images
    Input.copyTo(Output);
    Input_f.copyTo(Output_f);

    //uint8 image values - 0 ... 255
    //float image values - 0 ... 1      -> scaling necessary
    //cv::imshow("Input_f", Input_f);

    int imageWidth, imageHeight;
    imageWidth = Input_f.cols;
    imageHeight = Input_f.rows;

    //Create filter kernel - Laplace
    float filter[9] =
    {0,  1,  0,
     1, -4,  1,
     0,  1,  0 };

    //The filter is 3x3
    int filterWidth = 3;
    int filterSize = filterWidth * filterWidth;

    //Setup OpenCL Structure
    std::vector<cl::Platform> platforms;
    std::vector<cl::Device> devices;

    try
    {
        //Platform
        cl::Platform::get(&platforms);

        //Device
        platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);

        //Context
        cl::Context mycontext(devices);

        //Command Queue
        cl::CommandQueue queue(mycontext, NULL, NULL);

        //Image Format
        cl::ImageFormat format(CL_R, CL_FLOAT);                     //specifies how the image is read
                                                                    //single channel CL_FLOAT = 32 bit

        /*cl::ImageFormat format;
        format.image_channel_order = CL_R;
        format.image_channel_data_type = CL_FLOAT;*/

        //Create images on device
        cl::Image2D d_Input(mycontext,
            CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
            format,
            imageWidth,
            imageHeight,
            0 /*sizeof(float) * imageWidth*/,
            (float*)Input_f.data,
            NULL);

        cl::Image2D d_Output(mycontext,
            CL_MEM_WRITE_ONLY,
            format,
            imageWidth,
            imageHeight,
            0 /*sizeof(float) * imageWidth*/,
            NULL,
            NULL);

        //Create filter on device
        cl::Buffer d_filter(mycontext,
            CL_READ_ONLY_CACHE | CL_MEM_COPY_HOST_PTR,
            sizeof(float) * filterSize,
            (void*)&filter,
            NULL);

        //Create image sampler
        cl::Sampler sampler(mycontext,
            CL_FALSE,
            CL_ADDRESS_CLAMP_TO_EDGE,
            CL_FILTER_NEAREST,
            NULL);

        //Origin and Region
        cl::size_t<3> origin;
        origin[0] = 0;
        origin[1] = 0;
        origin[2] = 0;

        cl::size_t<3> region;
        origin[0] = imageWidth;
        origin[1] = imageHeight;
        origin[2] = 1;

        //Create Program
        std::ifstream programFile(PROGRAM_FILE);
        std::string programString(std::istreambuf_iterator<char>(programFile), (std::istreambuf_iterator<char>()));

        //std::cout << "Program String:\n" << programString << std::endl;

        cl::Program::Sources source(1, std::make_pair(programString.c_str(), programString.length() + 1));
        cl::Program program(mycontext, source, NULL);

        try
        {
            program.build(devices);
        }
        catch (cl::Error& esc)
        {
            if (esc.err() == CL_BUILD_PROGRAM_FAILURE)
            {
                // Check the build status
                cl_build_status status = program.getBuildInfo<CL_PROGRAM_BUILD_STATUS>(devices[0]);

                // Get the build log
                std::string buildlog = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0]);
                std::cerr << "Build log for " << buildlog << std::endl;
            }
        }

        //Create Kernel
        cl::Kernel kernel(program, KERNEL_FUNC, NULL);

        //Set Kernel Arguments
        kernel.setArg(0, d_Input);
        kernel.setArg(1, d_Output);
        kernel.setArg(2, imageWidth);
        kernel.setArg(3, imageHeight);
        kernel.setArg(4, d_filter);
        kernel.setArg(5, filterWidth);
        kernel.setArg(6, sampler);

        //Execute the Kernel
        cl::NDRange offset(0, 0);
        cl::NDRange global_size(imageHeight, imageWidth);       //1.height - 2.width
        cl::NDRange local_size(1, 1);
        queue.enqueueNDRangeKernel(kernel,
            offset,
            global_size,
            local_size);

        //Read back the output Image
        queue.enqueueReadImage(d_Output, CL_TRUE, origin, region, 0, 0, (float*)Output_f.data, NULL, NULL);

    }
    catch (cl::Error e)
    {
        std::cout << e.what() << ": Error code " << e.err() << std::endl;

    }

    //cv::waitKey();
    std::system("pause");
}
KERNEL CODE:
__kernel void laplacianFilter(__read_only image2d_t iimage,
                              __write_only image2d_t oimage,
                              int cols,
                              int rows, 
                              __constant float *filter, 
                              int windowSize,
                              sampler_t sampler)
{
   int col = get_global_id(0);         //columns
   int row = get_global_id(1);         //rows
   int halfWidth = windowSize/2;
   float4 pixelValue = {0.0, 0.0, 0.0, 0.0};
   float4 sum = 0.0f;
   int2 coords;
   int filterIdx = 0;

   //Convolute over the filter
   //Go over rows
   for (int i = -halfWidth; i <= halfWidth; i++)
   {
      coords.y = row + i;

      //Go over columns
      for (int j = -halfWidth; j <= halfWidth; j++)
      {
         coords.x = col + i;

         //Read pixel value and multiply by filter
         pixelValue = read_imagef(iimage, sampler, coords);
         sum = sum + pixelValue * filter[filterIdx++];
      }
   }

   //Write resulting value to correspoding pixel
   if (col < cols && row < rows)
   {
      write_imagef(oimage, (int2)(col, row), sum);
   }

}

最佳答案

https://www.khronos.org/registry/OpenCL/sdk/1.0/docs/man/xhtml/clEnqueueReadImage.html说你得到 CL_INVALID_VALUE 有两个原因:

  1. 如果 origin 和 region 指定的正在读取的区域超出范围,或者 ptr 为 NULL 值。
  2. 如果 image 是一个二维图像对象并且 origin[2] 不等于 0 或者 region[2] 不等于 1 或者 slice_pitch 不等于 0。

您遇到了#2。为什么?因为在你声明region之后,你又设置了origin的成员,让region没有初始化(并且region[2]不是1)。

关于c++ - 使用 OpenCL 的图像卷积中的参数大小无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56654881/

相关文章:

opencl - OpenCL 本地内存有限制吗?

Python, theano 运行时错误: could not initialize elemwise support

c++ - 为什么全局变量和静态变量被初始化为其默认值?

c++ - 数组显示比正常情况更多的结果

c++ - 在 C++ 中打开和显示图像?

php获取图像名称并添加到数据库?

python - OpenCV 3.2.0 windows,OpenCL 在 C++ 中显示设备,但在 python 中不显示

c++ - 将类类型作为异常抛出

c++ - 在阅读 callgrind 输出时需要帮助

html - 如何根据窗口大小更改图像大小