使用OpenCL进行卷积图像时参数大小无效

时间:2019-06-18 18:17:03

标签: c++ image opencl convolution

我正在尝试将OpenCV结合起来以简化有关图像和OpenCL的使用。 任务是加载图像并将其转换为具有浮点像素值的灰度。 然后我想用滤镜进行图像卷积。

当我尝试执行内核时,收到错误消息: “ 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);
   }

}

1 个答案:

答案 0 :(得分:1)

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

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

您正在遇到#2。为什么?因为在声明region之后,您再次设置origin的成员,而未初始化region(而region [2]不是1)。